【问题标题】:Creating SHA1 Hash from NSString从 NSString 创建 SHA1 哈希
【发布时间】:2011-11-26 02:08:51
【问题描述】:

如何从NSString 创建 SHA1。

假设 NSString 设置为:

NSString *message = @"Message";

我可以使用 PHP 创建一个带有 sha($message) 的 SHA1 哈希。但不幸的是,它在 Objective-C 中不是这样工作的。

【问题讨论】:

  • 你可以看看CC_SHA1。另见here
  • 谢谢亚历克斯,这对我有用!
  • @Alex:如果这是答案,您应该将其作为答案发布,以便其他 Alex 可以接受。
  • 一定要把它作为答案发布!
  • 我非常喜欢 hypercrypt 的回答,我把它打包成一个小 git repo。查看 NSString 类别 on Github. 也可以随意添加任何其他好的 NSString Crypto

标签: objective-c xcode hash sha1


【解决方案1】:

我在 NSString 上的一个类别中有这个(可在 https://github.com/hypercrypt/NSString-Hashes 获得):

#import <CommonCrypto/CommonDigest.h>

...

- (NSString *)sha1
{
    NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
    uint8_t digest[CC_SHA1_DIGEST_LENGTH];

    CC_SHA1(data.bytes, (CC_LONG)data.length, digest);

    NSMutableString *output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];

    for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
    {
        [output appendFormat:@"%02x", digest[i]];
    }

    return output;
}

从 Xcode 10.0 开始,您应该改用 import CommonCrypto,因为它现在在 Swift 中原生可用!如果您最近迁移到 Xcode 10.0 并使用旧方法,这可能是您进行更改的提示:

Command CompileSwift 失败,退出代码非零

【讨论】:

  • 不需要你导入 吗?
  • Xcode 4 抱怨以下行:CC_SHA1(data.bytes, data.length, digest);替换为:CC_SHA1(data.bytes, (CC_LONG) data.length, digest);
  • 你为什么用 CC_SHA1_DIGEST_LENGTH*2 初始化 mutableString 而不仅仅是 [NSMutableString string] ?
  • 它创建了一个可变字符串,其容量足以容纳整个输出字符串,这样在循环过程中就不需要扩展字符串的存储空间。如果您知道循环之前需要的大小(或上限),通常最好对 NSMutable* 类使用 *WithCapacity: 方法,因为可以在开始时分配正确的内存大小。
【解决方案2】:

我非常喜欢 hypercrypt 的回答,但有人鼓励我发表评论。

您可以查看CC_SHA1this 相关的 SO 问题。

【讨论】:

    【解决方案3】:
    - (NSString *)sha1:(NSString *)str {
    const char *cStr = [str UTF8String];
    unsigned char result[CC_SHA1_DIGEST_LENGTH];
    CC_SHA1(cStr, strlen(cStr), result);
    NSString *s = [NSString  stringWithFormat:
               @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
               result[0], result[1], result[2], result[3], result[4],
               result[5], result[6], result[7],
               result[8], result[9], result[10], result[11], result[12],
               result[13], result[14], result[15],
               result[16], result[17], result[18], result[19]
               ];
    
    return s;
    }
    

    【讨论】:

      【解决方案4】:

      试试这个:

      #import <CommonCrypto/CommonDigest.h>
      
      -(NSData *) selector
      {
          unsigned char hashBytes[CC_SHA1_DIGEST_LENGTH];
          CC_SHA1([dataToHash bytes], [dataToHash length], hashBytes);
          NSData *data = [[NSData alloc] initWithBytes:hashBytes length:CC_SHA1_DIGEST_LENGTH];
      }
      

      【讨论】:

        【解决方案5】:

        这是一个简洁且高度优化的NSString category

        @implementation NSString (PMUtils)
        - (NSString *)sha1Hash
        {
            NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
            NSData *hash = [data sha1Hash];
            return [hash hexString];
        } 
        @end
        
        @implementation NSData (PMUtils)
        - (NSString *) hexString
        {
            NSUInteger bytesCount = self.length;
            if (bytesCount) {
                static char const *kHexChars = "0123456789ABCDEF";
                const unsigned char *dataBuffer = self.bytes;
                char *chars = malloc(sizeof(char) * (bytesCount * 2 + 1));
                char *s = chars;
                for (unsigned i = 0; i < bytesCount; ++i) {
                    *s++ = kHexChars[((*dataBuffer & 0xF0) >> 4)];
                    *s++ = kHexChars[(*dataBuffer & 0x0F)];
                    dataBuffer++;
                }
                *s = '\0';
                NSString *hexString = [NSString stringWithUTF8String:chars];
                free(chars);
                return hexString;
            }
            return @"";
        }
        - (NSData *)sha1Hash
        {
            unsigned char digest[CC_SHA1_DIGEST_LENGTH];
            if (CC_SHA1(self.bytes, (CC_LONG)self.length, digest)) {
                return [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH];
            }
            return nil;
        }
        @end
        

        【讨论】:

          【解决方案6】:

          我花了一些时间将@hypercrypt 解决方案移植到 Swift,所以我决定与可能有同样问题的其他人分享它。

          需要注意的重要一点是您需要 CommonCrypto 库,但该库没有 Swift 模块。最简单的解决方法是将其导入桥接头:

          #import <CommonCrypto/CommonCrypto.h>
          

          在那里导入后,您不需要其他任何东西。只需使用提供的字符串扩展名:

          extension String
          {
              func sha1() -> String
              {
                  var selfAsSha1 = ""
          
                  if let data = self.dataUsingEncoding(NSUTF8StringEncoding)
                  {
                      var digest = [UInt8](count: Int(CC_SHA1_DIGEST_LENGTH), repeatedValue: 0)
                      CC_SHA1(data.bytes, CC_LONG(data.length), &digest)
          
                      for index in 0..<CC_SHA1_DIGEST_LENGTH
                      {
                          selfAsSha1 += String(format: "%02x", digest[Int(index)])
                      }
                  }
          
                  return selfAsSha1
              }
          }
          

          请注意,我的解决方案不会对 NSMutableString 在原始帖子中的保留容量生效。但是我怀疑任何人都会看到不同之处:)

          【讨论】:

          • 非常好,但为什么要扩展?
          • 嗯,主要是因为原始答案使用了类别,所以我脑海中的常见关联是扩展 :) 我认为这很容易,只需将所需的功能添加到字符串。我愿意寻求更好的解决方案:)
          【解决方案7】:

          我看到这篇文章中的答案有一些不同的可能改进。

          1. 切勿创建无前缀类别。如果你在你的库中实现了 -[NSString sha1Hash],而同一个应用程序中的另一个库实现了相同的方法,但语义略有不同怎么办?使用哪一个将是随机的,并导致难以诊断的错误。
          2. 如果你想要一个字符串,现在标准库中有 base64 编码。与手动构建十六进制字符串化相比,工作量更少。

          这是我的解决方案,adapted from the excellent SocketRocket library's SRHash.m

          // NSString+Sha1Digest.h
          #import <Foundation/Foundation.h>
          
          @interface NSString (LBDigest)
          - (NSString *)lb_digestString;
          @end
          
          @interface NSData (LBDigest)
          - (NSString *)lb_digestString;
          @end
          
          // NSString+SHA1Digest.m
          #import "NSString+Sha1Digest.h"
          #import <CommonCrypto/CommonDigest.h>
          
          static NSData *LBSHA1HashFromBytes(const char *bytes, size_t length)
          {
              uint8_t outputLength = CC_SHA1_DIGEST_LENGTH;
              unsigned char output[outputLength];
              CC_SHA1(bytes, (CC_LONG)length, output);
          
              return [NSData dataWithBytes:output length:outputLength];
          }
          
          static NSData *LBSHA1HashFromString(NSString *string)
          {
              size_t length = [string lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
              return LBSHA1HashFromBytes(string.UTF8String, length);
          }
          
          @implementation NSData (LBDigest)
          - (NSString *)lb_digestString;
          {
              return [LBSHA1HashFromBytes(self.bytes, self.length) base64EncodedStringWithOptions:0];
          }
          @end
          
          @implementation NSString (LBDigest)
          - (NSString *)lb_digestString;
          {
              return [LBSHA1HashFromString(self) base64EncodedStringWithOptions:0];
          }
          @end
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2010-09-07
            • 1970-01-01
            • 2016-10-12
            • 1970-01-01
            • 2011-11-20
            • 2010-12-04
            • 2020-03-04
            • 1970-01-01
            相关资源
            最近更新 更多