web-dev-qa-db-ja.com

SwiftでNSStringをSHA1でハッシュする方法は?

Objective-Cでは、次のようになります。

#include <sys/xattr.h>

@implementation NSString (reverse)

-(NSString*)sha1
{
    NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
    uint8_t digest[CC_SHA1_DIGEST_LENGTH];
    CC_SHA1(data.bytes, (int)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;
}

@end

私はSwiftでこのようなものが必要です、それは可能ですか?

作業例を示してください。

53
imike

Objective-Cコード(NSStringカテゴリを使用)は、Swift(String拡張機能を使用)に直接変換できます。

まず、「ブリッジングヘッダー」を作成して追加する必要があります

_#import <CommonCrypto/CommonCrypto.h>
_

次に:

_extension String {
    func sha1() -> String {
        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)
        let output = NSMutableString(capacity: Int(CC_SHA1_DIGEST_LENGTH))
        for byte in digest {
            output.appendFormat("%02x", byte)
        }
        return output as String
    }
}

println("Hello World".sha1())
_

これは少し短く書くことができ、Swifterは

_extension String {
    func sha1() -> String {
        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)
        let hexBytes = map(digest) { String(format: "%02hhx", $0) }
        return "".join(hexBytes)
    }
}
_

Swift 2:の更新

_extension String {
    func sha1() -> String {
        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)
        let hexBytes = digest.map { String(format: "%02hhx", $0) }
        return hexBytes.joinWithSeparator("")
    }
}
_

16進エンコード文字列ではなく、Base-64エンコード文字列を返すには、単に置き換えます

_        let hexBytes = digest.map { String(format: "%02hhx", $0) }
        return hexBytes.joinWithSeparator("")
_

_        return NSData(bytes: digest, length: digest.count).base64EncodedStringWithOptions([])
_

Swift 3:の更新

_extension String {
    func sha1() -> String {
        let data = self.data(using: String.Encoding.utf8)!
        var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH))
        data.withUnsafeBytes { 
            _ = CC_SHA1($0, CC_LONG(data.count), &digest)
        }
        let hexBytes = digest.map { String(format: "%02hhx", $0) }
        return hexBytes.joined()
    }
}
_

16進エンコード文字列ではなく、Base-64エンコード文字列を返すには、単に置き換えます

_        let hexBytes = digest.map { String(format: "%02hhx", $0) }
        return hexBytes.joined()
_

によって

_        return Data(bytes: digest).base64EncodedString()
_

Swift 4 ::の更新

ブリッジングヘッダーファイルは不要になりました。代わりに_import CommonCrypto_を使用できます。

_import CommonCrypto

extension String {
    func sha1() -> String {
        let data = Data(self.utf8)
        var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH))
        data.withUnsafeBytes { 
            _ = CC_SHA1($0, CC_LONG(data.count), &digest)
        }
        let hexBytes = digest.map { String(format: "%02hhx", $0) }
        return hexBytes.joined()
    }
}
_

Swift 5:の更新

Data.withUnsafeBytes()メソッドはUnsafeRawBufferPointer toでクロージャーを呼び出し、baseAddressを使用して初期関数をC関数に渡します。

_import CommonCrypto

extension String {
    func sha1() -> String {
        let data = Data(self.utf8)
        var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH))
        data.withUnsafeBytes { 
            _ = CC_SHA1($0.baseAddress, CC_LONG(data.count), &digest)
        }
        let hexBytes = digest.map { String(format: "%02hhx", $0) }
        return hexBytes.joined()
    }
}
_
153
Martin R

NSDataとして結果を取得するには、<CommonCrypto/CommonCrypto.h>ブリッジングヘッダー:

extension NSData {

    func sha1() -> NSData? {
        let len = Int(CC_SHA1_DIGEST_LENGTH)
        let digest = UnsafeMutablePointer<UInt8>.alloc(len)
        CC_SHA1(bytes, CC_LONG(length), digest)
        return NSData(bytesNoCopy: UnsafeMutablePointer<Void>(digest), length: len)
    }
}

適切なポインタ割り当ても使用します。次のように呼び出します。

myString.dataUsingEncoding(NSUTF8StringEncoding)?.sha1()

NSDataの16進表現が必要な場合は、他の answer をご覧ください。

4
Erik Aigner

はい、可能です。このクラスをプロジェクトにコピーしてください。 https://github.com/idrougge/sha1-Swift

そして、次のように簡単になります。

 SHA1.hexString(from: "myPhrase" )!

Swift 3およびSwift 4。でテスト済み

4
MrMins

Sha1を使用して3つのステップで文字列を暗号化するロジックを抽出できます。

  1. 文字列をデータオブジェクトに変換
  2. SHA1関数を使用してデータを暗号化する
  3. データオブジェクトを16進文字列に変換します

私見では、はるかに読みやすく、このバージョンはNSDataを必要としません。

    extension String {

        var sha1: String {
            guard let data = data(using: .utf8, allowLossyConversion: false) else {
                // Here you can just return empty string or execute fatalError with some description that this specific string can not be converted to data
            }
            return data.digestSHA1.hexString
        }

    }

    fileprivate extension Data {

        var digestSHA1: Data {
            var bytes: [UInt8] = Array(repeating: 0, count: Int(CC_SHA1_DIGEST_LENGTH))

            withUnsafeBytes {
                _ = CC_SHA1($0, CC_LONG(count), &bytes)
            }

            return Data(bytes: bytes)
        }

        var hexString: String {
            return map { String(format: "%02x", UInt8($0)) }.joined()
        }

    }
1

IOS13にCryptoKitが追加されたため、ネイティブSwift= API:

import Foundation
import CryptoKit

// CryptoKit.Digest utils
extension Digest {
    var bytes: [UInt8] { Array(makeIterator()) }
    var data: Data { Data(bytes) }

    var hexStr: String {
        bytes.map { String(format: "%02X", $0) }.joined()
    }
}

func example() {
    guard let data = "hello world".data(using: .utf8) else { return }
    let digest = Insecure.SHA1.hash(data: data)
    print(digest.data) // 20 bytes
    print(digest.hexStr) // 2AAE6C35C94FCFB415DBE95F408B9CE91EE846ED
}
1
duan

はい、可能です:Objective-cコードをSwiftからアクセス可能にする

ドキュメント を参照してください。

メリットが得られない場合(Swift固有の機能を使用する場合など)は、Swiftで書き換えることを避けます。

また、私が取り組んでいるプロジェクトでは、ハッシュを処理するためにあなたのものに似たいくつかのObjective-Cコードを使用しました。始めはSwiftで書き始めたのですが、古いobj-cを再利用する方が簡単で優れていることがわかりました。

0
Antonio