web-dev-qa-db-ja.com

NSStringからSHA1ハッシュを作成する

NSStringからSHA1を作成するにはどうすればよいですか。

NSStringが次のように設定されているとしましょう:

_NSString *message = @"Message";
_

PHP=を使用してsha($message)を使用してSHA1ハッシュを作成できます。

42
Alex van Rijs

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は、ゼロ以外の終了コードで失敗しました

90
hypercrypt

Hypercryptの答えはとても気に入っていますが、コメントを投稿することをお勧めします。

CC_SHA1 、または this 関連SO質問。

16
Alex
- (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;
}
12
virata

Hypercryptの答えがとても好きなので、小さなgitリポジトリにパッケージ化しました。 NSStringカテゴリを確認してください Githubで

また、他の優れたNSString暗号で自由に追加してください。

6
atreat

@hypercryptソリューションをSwiftに移植するのに少し時間がかかったので、同じ問題があるかもしれない他の人と共有することにしました。

注意すべき重要な点は、CommonCryptoライブラリが必要なことですが、そのライブラリにはSwiftモジュールがありません。ブリッジヘッダーにインポートするのが最も簡単な回避策です。

#import <CommonCrypto/CommonCrypto.h>

そこにインポートしたら、他に何も必要ありません。提供されているString拡張機能を使用するだけです:

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が持っていた容量の予約には影響しません。しかし、私は誰も違いを見ることを疑います:)

4
hris.to

これを試して:

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

簡潔で高度に最適化された NSStringカテゴリ

@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
1
Peter

この投稿の回答にいくつかの異なる改善が見られます。

  1. 接頭辞のないカテゴリを作成しないでください。ライブラリに-[NSString sha1Hash]を実装し、同じアプリの別のライブラリがわずかに異なるセマンティクスで同じメソッドを実装するとどうなりますか?どれが使用されるかはランダムであり、診断が困難なエラーにつながります。
  2. 文字列が必要な場合、最近の標準ライブラリにはbase64エンコードがあります。 16進文字列化を手動で作成するよりも作業が少なくなります。

ここに私の解決策があります 優れたSocketRocketライブラリの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
1
nevyn