从NSString创建SHA1哈希

时间:2011-09-27 13:56:36

标签: objective-c xcode hash sha1

如何从NSString创建SHA1。

假设NSString设置为:

NSString *message = @"Message";

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

8 个答案:

答案 0 :(得分:89)

我在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并使用旧方法,那么这可能是您进行更改的提示:

  

命令CompileSwift失败并返回非零退出代码

答案 1 :(得分:16)

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

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

答案 2 :(得分:12)

- (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;
}

答案 3 :(得分:6)

我非常喜欢hypercrypt的答案,我将它打包成一个小git repo。查看NSString类别 on Github.

也可以随意添加任何其他好的NSString Crypto

答案 4 :(得分:4)

我花了一些时间将@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原始帖子中的预留容量。但是,我怀疑任何人都会看到差异:)

答案 5 :(得分:3)

试试这个:

#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];
}

答案 6 :(得分:1)

这是一个简洁且高度优化的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

答案 7 :(得分:1)

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

  1. 永远不要做一个没有前缀的类别。如果在库中实现 - [NSString sha1Hash],并且同一个应用程序中的另一个库实现相同的方法,语义略有不同,该怎么办?使用哪一个将是随机的,并导致难以诊断的错误。
  2. 如果你想要一个字符串,现在标准库中有base64编码。比手动构建十六进制字符串更少的工作。
  3. 这是我的解决方案,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