web-dev-qa-db-de.com

Schnelle Implementierung der HMAC- und SHA1-Verschlüsselung

Ich bin relativ neu bei Swift und bin mit HMAC und SHA1 verschlüsselt. Ich habe folgende Antwort gefunden https://stackoverflow.com/a/24411522/4188344 , aber ich kann nicht herausfinden, wie ich dies richtig implementieren kann. Jede Hilfe wäre großartig.

13
David Wood

Problem gelöst! Zuerst habe ich die String-Funktion nicht richtig verwendet ... Ich endete damit:

    let hmacResult:String = "myStringToHMAC".hmac(HMACAlgorithm.SHA1, key: "myKey")

Dann hatte ich vergessen, dass ich das hmac-Ergebnis als Base64-Codierung verwenden musste. Also habe ich die in meiner Frage verknüpfte String-Funktion geändert, um ...

enum HMACAlgorithm {
    case MD5, SHA1, SHA224, SHA256, SHA384, SHA512

    func toCCHmacAlgorithm() -> CCHmacAlgorithm {
        var result: Int = 0
        switch self {
        case .MD5:
            result = kCCHmacAlgMD5
        case .SHA1:
            result = kCCHmacAlgSHA1
        case .SHA224:
            result = kCCHmacAlgSHA224
        case .SHA256:
            result = kCCHmacAlgSHA256
        case .SHA384:
            result = kCCHmacAlgSHA384
        case .SHA512:
            result = kCCHmacAlgSHA512
        }
        return CCHmacAlgorithm(result)
    }

    func digestLength() -> Int {
        var result: CInt = 0
        switch self {
        case .MD5:
            result = CC_MD5_DIGEST_LENGTH
        case .SHA1:
            result = CC_SHA1_DIGEST_LENGTH
        case .SHA224:
            result = CC_SHA224_DIGEST_LENGTH
        case .SHA256:
            result = CC_SHA256_DIGEST_LENGTH
        case .SHA384:
            result = CC_SHA384_DIGEST_LENGTH
        case .SHA512:
            result = CC_SHA512_DIGEST_LENGTH
        }
        return Int(result)
    }
}

extension String {
    func hmac(algorithm: HMACAlgorithm, key: String) -> String {
        let cKey = key.cStringUsingEncoding(NSUTF8StringEncoding)
        let cData = self.cStringUsingEncoding(NSUTF8StringEncoding)
        var result = [CUnsignedChar](count: Int(algorithm.digestLength()), repeatedValue: 0)
        CCHmac(algorithm.toCCHmacAlgorithm(), cKey!, strlen(cKey!), cData!, strlen(cData!), &result)
        var hmacData:NSData = NSData(bytes: result, length: (Int(algorithm.digestLength())))
        var hmacBase64 = hmacData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding76CharacterLineLength)
        return String(hmacBase64)
    }
}

Dies gibt mir das richtige Ergebnis von 

lGCtbW+DNHFraNoxPGK3trgM/98=
31
David Wood

Hier ist die Lösung von @David Wood für Swift 3 aktualisiert:

enum HMACAlgorithm {
    case MD5, SHA1, SHA224, SHA256, SHA384, SHA512

    func toCCHmacAlgorithm() -> CCHmacAlgorithm {
        var result: Int = 0
        switch self {
        case .MD5:
            result = kCCHmacAlgMD5
        case .SHA1:
            result = kCCHmacAlgSHA1
        case .SHA224:
            result = kCCHmacAlgSHA224
        case .SHA256:
            result = kCCHmacAlgSHA256
        case .SHA384:
            result = kCCHmacAlgSHA384
        case .SHA512:
            result = kCCHmacAlgSHA512
        }
        return CCHmacAlgorithm(result)
    }

    func digestLength() -> Int {
        var result: CInt = 0
        switch self {
        case .MD5:
            result = CC_MD5_DIGEST_LENGTH
        case .SHA1:
            result = CC_SHA1_DIGEST_LENGTH
        case .SHA224:
            result = CC_SHA224_DIGEST_LENGTH
        case .SHA256:
            result = CC_SHA256_DIGEST_LENGTH
        case .SHA384:
            result = CC_SHA384_DIGEST_LENGTH
        case .SHA512:
            result = CC_SHA512_DIGEST_LENGTH
        }
        return Int(result)
    }
}

extension String {
    func hmac(algorithm: HMACAlgorithm, key: String) -> String {
        let cKey = key.cString(using: String.Encoding.utf8)
        let cData = self.cString(using: String.Encoding.utf8)
        var result = [CUnsignedChar](repeating: 0, count: Int(algorithm.digestLength()))
        CCHmac(algorithm.toCCHmacAlgorithm(), cKey!, Int(strlen(cKey!)), cData!, Int(strlen(cData!)), &result)
        let hmacData:NSData = NSData(bytes: result, length: (Int(algorithm.digestLength())))
        let hmacBase64 = hmacData.base64EncodedString(options: NSData.Base64EncodingOptions.lineLength76Characters)
        return String(hmacBase64)
    }
}

// usage:
let hmacResult: String = "myStringToHMAC".hmac(algorithm: HMACAlgorithm.SHA1, key: "foo")
13

So erstellen Sie eine Swift 4-Erweiterung:

Header-Datei überbrücken

#import <CommonCrypto/CommonCrypto.h>

Code

extension String {

    func hmac(key: String) -> String {
        var digest = [UInt8](repeating: 0, count: Int(CC_SHA1_DIGEST_LENGTH))
        CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1), key, key.count, self, self.count, &digest)
        let data = Data(bytes: digest)
        return data.map { String(format: "%02hhx", $0) }.joined()
    }

}

Beispiel

let result = "test".hmac(key: "test")

Ergebnis

0c94515c15e5095b8a87a50ba0df3bf38ed05fe6
10
sundance

Wenn Sie dasselbe Ergebnis im Hexadezimalformat erhalten möchten, können Sie die folgende Erweiterung verwenden: 

extension String {
    func hmac(algorithm: HMACAlgorithm, key: String) -> String {
        let cKey = key.cStringUsingEncoding(NSUTF8StringEncoding)
        let cData = self.cStringUsingEncoding(NSUTF8StringEncoding)
        var result = [CUnsignedChar](count: Int(algorithm.digestLength()), repeatedValue: 0)
        let length : Int = Int(strlen(cKey!))
        let data : Int = Int(strlen(cData!))
        CCHmac(algorithm.toCCHmacAlgorithm(), cKey!,length , cData!, data, &result)

        let hmacData:NSData = NSData(bytes: result, length: (Int(algorithm.digestLength())))

        var bytes = [UInt8](count: hmacData.length, repeatedValue: 0)
        hmacData.getBytes(&bytes, length: hmacData.length)

        var hexString = ""
        for byte in bytes {
            hexString += String(format:"%02hhx", UInt8(byte))
        }
        return hexString
    }
}
8
Kautham Krishna

Ich habe dieses Modul, das ich zu meinem Projekt hinzugefügt habe, als Framework verwendet:

https://github.com/CryptoCoinSwift/SHA256-Swift

Und ich habe auch die folgende Erweiterung von String zu SHA256.Swift hinzugefügt:

public extension String {

    func sha256(key: String) -> String {
        let inputData: NSData = self.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
        let keyData: NSData = key.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!

        let algorithm = HMACAlgorithm.SHA256
        let digestLen = algorithm.digestLength()
        let result = UnsafeMutablePointer<CUnsignedChar>.alloc(digestLen)

        CCHmac(algorithm.toCCEnum(), keyData.bytes, UInt(keyData.length), inputData.bytes, UInt(inputData.length), result)
        let data = NSData(bytes: result, length: digestLen)
        result.destroy()
        return data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
    }

}

Auf diese Weise kann aus einer String eine Base64-codierte Signatur erzeugt werden:

let signature: String = "\(payload)".sha256(secretKey)
7
maksimov

Ich habe die obigen Antworten geprüft und fand sie so lang.

Lösung: Ich habe einen Drittanbieter: IDZSwiftCommonCrypto

Pod verwenden: pod 'IDZSwiftCommonCrypto'

und verwenden Sie die folgende Funktion, um die gewünschte Ausgabe zu erzielen:

func getHMacSHA1(forMessage message: String, key: String) -> String? {
    let hMacVal = HMAC(algorithm: HMAC.Algorithm.sha1, key: key).update(string: message)?.final()
    if let encryptedData = hMacVal {
        let decData = NSData(bytes: encryptedData, length: Int(encryptedData.count))
        let base64String = decData.base64EncodedString(options: .lineLength64Characters)
        print("base64String: \(base64String)")
        return base64String
    } else {
        return nil
    }
}

Um das Ergebnis zu überprüfen, verwenden Sie folgende Website:

https://hash.online-convert.com/sha1-generator

Getestet in Swift 4.0

0
g212gs

In Swift 4 benötigen Sie die Bibliothek CommonCrypto https://forums.developer.Apple.com/thread/46477

#import <CommonCrypto/CommonCrypto.h>

Und Sie können eine Erweiterung mit base64 erstellen

extension String {
    func hmac(key: String) -> String {
        var digest = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
        CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), key, key.count, self, self.count, &digest)
        let data = Data(bytes: digest)
        return data.base64EncodedString(options: Data.Base64EncodingOptions(rawValue: 0))
    }
}

Usege:

print("HMAC_SHA256:".hmac(key: "MyKey"))

Ergebnis:

6GM2evJeNZYdP3OjPcKmg8TDzILSQAjy4NGhCHnBH5M=
0
Sergei

Verwendung roher Bytes für Schlüssel und Nachricht und keine Kodierung in utf8:

    static func getHmac_X_Sha1() -> [UInt8] {

        let msg:[UInt8] = message_uint8;
        let msgLen = message_uint8.count;
        let digestLen = Int(CC_SHA1_DIGEST_LENGTH)
        let digest = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
        let keyStr:[UInt8] = key_uint8
        let keyLen = key_uint8.count

        CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1), keyStr, keyLen, msg, msgLen, digest)


        //Build a hex string of result
        let hash_hex_string = NSMutableString()
        for i in 0..<digestLen {
            hash_hex_string.appendFormat("%02x", result[i])
         }
         //print(hash_hex_string)
         result.deallocate()

         // Resolve hash_hex_string to byte array
         let hash_bytes:[UInt8] = hexStringToBytes(String(hash_hex_string))
         return hash_bytes
     }



    //Return a byte array from hex string input
     private static func hexStringToBytes(_ string: String) -> [UInt8]? {
        let length = string.characters.count
        if length & 1 != 0 {
            return nil
        }
        var bytes = [UInt8]()
        bytes.reserveCapacity(length/2)
        var index = string.startIndex
        for _ in 0..<length/2 {
            let nextIndex = string.index(index, offsetBy: 2)
            if let b = UInt8(string[index..<nextIndex], radix: 16) {
                bytes.append(b)
            } else {
                return nil
            }
            index = nextIndex
        }
        return bytes
     }
0
Matt