Implementing HMAC and SHA1 encryption in swift

后端 未结 8 1249
借酒劲吻你
借酒劲吻你 2020-11-29 01:42

I am relatively new to Swift and i\'m stuck encrypting using HMAC and SHA1. I Found the following answer https://stackoverflow.com/a/24411522/4188344 but i can\'t work out h

相关标签:
8条回答
  • 2020-11-29 02:05

    Here is how to create a Swift 4 extension:

    Bridging headers file

    #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()
        }
    
    }
    

    Example

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

    Result

    0c94515c15e5095b8a87a50ba0df3bf38ed05fe6
    
    0 讨论(0)
  • 2020-11-29 02:11

    Problem solved! First off i wasn't using the string function properly... I ended up with this:

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

    Then I had forgotten I needed to base64 encode the hmac result. So i modified the string function linked in my question to...

    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)
        }
    }
    

    This is giving me the correct result of

    lGCtbW+DNHFraNoxPGK3trgM/98=
    
    0 讨论(0)
  • 2020-11-29 02:18

    I have used this module which I added to my project as a framework:

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

    And I have also added the following String extension to SHA256.swift:

    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)
        }
    
    }
    

    This way producing a base64-encoded signature from a String can be done like this:

    let signature: String = "\(payload)".sha256(secretKey)
    
    0 讨论(0)
  • 2020-11-29 02:22

    In Swift 4 You need library CommonCrypto https://forums.developer.apple.com/thread/46477

    #import <CommonCrypto/CommonCrypto.h>
    

    And you can create extension with base64

    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"))
    

    Result:

    6GM2evJeNZYdP3OjPcKmg8TDzILSQAjy4NGhCHnBH5M=
    
    0 讨论(0)
  • 2020-11-29 02:23

    Using raw bytes for key and message and not encoding to 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 讨论(0)
  • 2020-11-29 02:24

    I have checked the above answers and found it so lengthy.

    Solution: I got third party: IDZSwiftCommonCrypto

    Use pod: pod 'IDZSwiftCommonCrypto'

    and use the following function to achieve desired output:

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

    For check the result use following website:

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

    Tested in Swift 4.0

    0 讨论(0)
提交回复
热议问题