General forum

I am trying to create an HMAC SHA-1 hash of a string in Swift, but cannot figure out how to interact with the API, as it does not seem to import the CommonCrypto environment. I tried various forms of "import CommonCrypto" and created the bridge header file, but none of this changed the situation.

The strange thing is that if I create an Objective-C class, I can interact with the API without problems, so this seems to be unique to Swift.

Also, if someone could tell me what is equivalent to uint8_t digest[CC_SHA1_DIGEST_LENGTH] in Swift, I would be very grateful

+29
swift hash macos commoncrypto hmacsha1
Jun 07 '14 at 16:55
source share
9 answers

You can do it in Swift. Just make sure you add #import <CommonCrypto/CommonHMAC.h> to the Objective-C bridge.

 enum CryptoAlgorithm { case MD5, SHA1, SHA224, SHA256, SHA384, SHA512 var HMACAlgorithm: 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) } var digestLength: Int { var result: Int32 = 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: CryptoAlgorithm, key: String) -> String { let str = self.cStringUsingEncoding(NSUTF8StringEncoding) let strLen = Int(self.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)) let digestLen = algorithm.digestLength let result = UnsafeMutablePointer<CUnsignedChar>.alloc(digestLen) let keyStr = key.cStringUsingEncoding(NSUTF8StringEncoding) let keyLen = Int(key.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)) CCHmac(algorithm.HMACAlgorithm, keyStr!, keyLen, str!, strLen, result) let digest = stringFromResult(result, length: digestLen) result.dealloc(digestLen) return digest } private func stringFromResult(result: UnsafeMutablePointer<CUnsignedChar>, length: Int) -> String { var hash = NSMutableString() for i in 0..<length { hash.appendFormat("%02x", result[i]) } return String(hash) } } 
+58
Jun 25 '14 at 14:33
source share

Try this for Swift 3.1 :

 enum CryptoAlgorithm { case MD5, SHA1, SHA224, SHA256, SHA384, SHA512 var HMACAlgorithm: 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) } var digestLength: Int { var result: Int32 = 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: CryptoAlgorithm, key: String) -> String { let str = self.cString(using: String.Encoding.utf8) let strLen = Int(self.lengthOfBytes(using: String.Encoding.utf8)) let digestLen = algorithm.digestLength let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen) let keyStr = key.cString(using: String.Encoding.utf8) let keyLen = Int(key.lengthOfBytes(using: String.Encoding.utf8)) CCHmac(algorithm.HMACAlgorithm, keyStr!, keyLen, str!, strLen, result) let digest = stringFromResult(result: result, length: digestLen) result.deallocate(capacity: digestLen) return digest } private func stringFromResult(result: UnsafeMutablePointer<CUnsignedChar>, length: Int) -> String { let hash = NSMutableString() for i in 0..<length { hash.appendFormat("%02x", result[i]) } return String(hash) } } 

Remember to add #import <CommonCrypto/CommonHMAC.h> to Header.h

+4
May 9 '17 at 6:00
source share

Swift can determine how to map Obj-C structures, but not so much for C direct functions. Apple has provided some bindings for things like GCD and AudioToolbox, but not all. CommonCrypto doesn't seem to have the appropriate bindings yet.

In this case, I would recommend writing your own base wrappers in Obj-C, and then using these wrapper classes in Swift.

For example, you can create an HMAC class in Obj-C:

 // This enum is in HMAC.h typedef NS_ENUM(NSInteger, HMACAlgorithm) { SHA1, MD5, SHA256, SHA384, SHA512, SHA224 }; // Class methods here + (NSData *)calculateWithAlgorithm:(HMACAlgorithm)algorithm forKey:(const void *)key andData:(const void *)data { NSInteger digestLength = [self digestLengthForAlgorithm:algorithm]; unsigned char hmac[digestLength]; CCHmac(algorithm, &key, strlen(key), &data, strlen(data), &hmac); NSData *hmacBytes = [NSData dataWithBytes:hmac length:sizeof(hmac)]; return hmacBytes; } + (NSInteger)digestLengthForAlgorithm:(HMACAlgorithm)algorithm { switch (algorithm) { case MD5: return CC_MD5_DIGEST_LENGTH; case SHA1: return CC_SHA1_DIGEST_LENGTH; case SHA224: return CC_SHA224_DIGEST_LENGTH; case SHA256: return CC_SHA256_DIGEST_LENGTH; case SHA384: return CC_SHA384_DIGEST_LENGTH; case SHA512: return CC_SHA512_DIGEST_LENGTH; default: return 0; } } 

Then in Swift:

 class SwiftHMAC { // Swift will automatically pull the enum from Obj-C func calculate(algorithm:HMACAlgorithm, key:Byte[], data:Byte[]) -> Byte[] { let computedHMAC = HMAC.calculateWithAlgorithm(algorithm, forKey: key, andData: data) var rawBytes = Byte[](count: computedHMAC.length, repeatedValue: 0) computedHMAC.getBytes(&rawBytes) return rawBytes } } 

Remember to add #import "HMAC.h" to your Swift bridge header, as well as #import "<##Your-Project-Name##>-Swift.h" to the Obj-C implementation file (.m).

+3
Jun 07 '14 at 18:05
source share

Below is the revised version sent by @ jernej-strasner

 enum HMACAlgorithm { case MD5, SHA1, SHA224, SHA256, SHA384, SHA512 func toCCEnum() -> 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 digest(algorithm: HMACAlgorithm, key: String) -> String! { let str = self.cStringUsingEncoding(NSUTF8StringEncoding) let strLen = UInt(self.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)) let digestLen = algorithm.digestLength() let result = UnsafeMutablePointer<CUnsignedChar>.alloc(digestLen) let keyStr = key.cStringUsingEncoding(NSUTF8StringEncoding) let keyLen = UInt(key.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)) CCHmac(algorithm.toCCEnum(), keyStr!, keyLen, str!, strLen, result) var hash = NSMutableString() for i in 0..<digestLen { hash.appendFormat("%02x", result[i]) } result.destroy() return String(hash) } } 
+3
09 Oct '14 at 19:43
source share

I wanted to keep things minimal. Avoid the added complexity of creating a generic class that could handle all the different types of digest, and instead just have a small method that I could fall into the class if necessary. I also prefer to avoid adding extensions to the main classes.

Add the following to your -Bridging-Header.h file:

 #import <CommonCrypto/CommonHMAC.h> 

Then, in the class that needs to call CCHmac() , add a private method:

 private func hmac(string: NSString, key: NSData) -> NSData { let keyBytes = UnsafePointer<CUnsignedChar>(key.bytes) let data = string.cStringUsingEncoding(NSUTF8StringEncoding) let dataLen = Int(string.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)) let digestLen = Int(CC_SHA1_DIGEST_LENGTH) let result = UnsafeMutablePointer<CUnsignedChar>.alloc(digestLen) CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1), keyBytes, key.length, data, dataLen, result); return NSData(bytes: result, length: digestLen) } 

If I need another CCHmacAlgorithm , I would just replace the two constants in this method with the appropriate ones. In my case, I needed kCCHmacAlgSHA256 and CC_SHA256_DIGEST_LENGTH .

Thanks to Jernej Strasner and others for the other answers, I just wanted something simpler for my case.

+3
Mar 18 '16 at 5:00
source share

after swift 1.2 replace lines in func digest

 let strLen = UInt(self.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)) let keyLen = UInt(key.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)) 

by

 let strLen = self.lengthOfBytesUsingEncoding(NSUTF8StringEncoding) let keyLen = key.lengthOfBytesUsingEncoding(NSUTF8StringEncoding) 
+2
Apr 14 '15 at 2:00
source share

This is the complete source, "How to Import CommonCrypto into a Swift Project without Obj-c briging Header," modified for Swift 3.0. The actual work with the code is "Michael Isaev."

 // // HMAC.swift // // Created by Mihael Isaev on 21.04.15. // Copyright (c) 2014 Mihael Isaev inc. All rights reserved. // // *********************************************************** // // How to import CommonCrypto in Swift project without Obj-c briging header // // To work around this create a directory called CommonCrypto in the root of the project using Finder. // In this directory create a file name module.map and copy the following into the file. // You will need to alter the paths to ensure they point to the headers on your system. // // module CommonCrypto [system] { // header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/CommonCrypto/CommonCrypto.h" // export * // } // To make this module visible to Xcode, go to Build Settings, Swift Compiler – Search Paths // and set Import Paths to point to the directory that contains the CommonCrypto directory. // // You should now be able to use import CommonCrypto in your Swift code. // // You have to set the Import Paths in every project that uses your framework so that Xcode can find it. // // *********************************************************** // // Modification for Swift 3.0 by Sanjay Sampat on 04.Jan.2017 // // *********************************************************** import Foundation import CommonCrypto extension String { var md5: String { return HMAC.hash(inp: self, algo: HMACAlgo.MD5) } var sha1: String { return HMAC.hash(inp: self, algo: HMACAlgo.SHA1) } var sha224: String { return HMAC.hash(inp: self, algo: HMACAlgo.SHA224) } var sha256: String { return HMAC.hash(inp: self, algo: HMACAlgo.SHA256) } var sha384: String { return HMAC.hash(inp: self, algo: HMACAlgo.SHA384) } var sha512: String { return HMAC.hash(inp: self, algo: HMACAlgo.SHA512) } func aesEncrypt(key:String, iv:String, options:Int = kCCOptionPKCS7Padding) -> String? { if let keyData = key.data(using: String.Encoding.utf8), let data = self.data(using: String.Encoding.utf8), let cryptData = NSMutableData(length: Int((data.count)) + kCCBlockSizeAES128) { let keyLength = size_t(kCCKeySizeAES128) let operation: CCOperation = UInt32(kCCEncrypt) let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128) let options: CCOptions = UInt32(options) var numBytesEncrypted :size_t = 0 let base64cryptStringOut = keyData.withUnsafeBytes {(keyBytes: UnsafePointer<CChar>)->String? in return data.withUnsafeBytes {(dataBytes: UnsafePointer<CChar>)->String? in let cryptStatus = CCCrypt(operation, algoritm, options, keyBytes, keyLength, iv, dataBytes, data.count, cryptData.mutableBytes, cryptData.length, &numBytesEncrypted) if UInt32(cryptStatus) == UInt32(kCCSuccess) { cryptData.length = Int(numBytesEncrypted) let base64cryptString = cryptData.base64EncodedString(options: .lineLength64Characters) return base64cryptString } else { return nil } } } return base64cryptStringOut } return nil } func aesDecrypt(key:String, iv:String, options:Int = kCCOptionPKCS7Padding) -> String? { if let keyData = key.data(using: String.Encoding.utf8), let data = NSData(base64Encoded: self, options: .ignoreUnknownCharacters), let cryptData = NSMutableData(length: Int((data.length)) + kCCBlockSizeAES128) { let keyLength = size_t(kCCKeySizeAES128) let operation: CCOperation = UInt32(kCCDecrypt) let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128) let options: CCOptions = UInt32(options) var numBytesEncrypted :size_t = 0 let unencryptedMessageOut = keyData.withUnsafeBytes {(keyBytes: UnsafePointer<CChar>)->String? in let cryptStatus = CCCrypt(operation, algoritm, options, keyBytes, keyLength, iv, data.bytes, data.length, cryptData.mutableBytes, cryptData.length, &numBytesEncrypted) if UInt32(cryptStatus) == UInt32(kCCSuccess) { cryptData.length = Int(numBytesEncrypted) let unencryptedMessage = String(data: cryptData as Data, encoding:String.Encoding.utf8) return unencryptedMessage } else { return nil } } return unencryptedMessageOut } return nil } } public struct HMAC { static func hash(inp: String, algo: HMACAlgo) -> String { if let stringData = inp.data(using: String.Encoding.utf8, allowLossyConversion: false) { return hexStringFromData(input: digest(input: stringData as NSData, algo: algo)) } return "" } private static func digest(input : NSData, algo: HMACAlgo) -> NSData { let digestLength = algo.digestLength() var hash = [UInt8](repeating: 0, count: digestLength) switch algo { case .MD5: CC_MD5(input.bytes, UInt32(input.length), &hash) break case .SHA1: CC_SHA1(input.bytes, UInt32(input.length), &hash) break case .SHA224: CC_SHA224(input.bytes, UInt32(input.length), &hash) break case .SHA256: CC_SHA256(input.bytes, UInt32(input.length), &hash) break case .SHA384: CC_SHA384(input.bytes, UInt32(input.length), &hash) break case .SHA512: CC_SHA512(input.bytes, UInt32(input.length), &hash) break } return NSData(bytes: hash, length: digestLength) } private static func hexStringFromData(input: NSData) -> String { var bytes = [UInt8](repeating: 0, count: input.length) input.getBytes(&bytes, length: input.length) var hexString = "" for byte in bytes { hexString += String(format:"%02x", UInt8(byte)) } return hexString } } enum HMACAlgo { case MD5, SHA1, SHA224, SHA256, SHA384, SHA512 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) } } 

Below is an example of use.

  // TEST for Encryption and Decryption through HMAC Swift 3.0 let iv = "iv-salt-Sanjay--" // fixed 16 chars. let cryptoKeyString = "01234567890123456789012345678901" let originalString = "My Name is Sanjay Sampat, Password is IL0ve2view2Kill@4#" print("Original String: \(originalString)") if let encodedString = originalString.aesEncrypt(key: cryptoKeyString, iv: iv){ print("String Encoded: \(encodedString)") if let decryptedString = encodedString.aesDecrypt(key: cryptoKeyString, iv: iv) { print("String Decoded: \(decryptedString)") } else{ print("Decoding failed") } } else{ print("Encoding failed") } // Example To create sha1 from string let testString = "This is string to test sha1 hash string." let sha1Digest = testString.sha1 print("sha1-hash-string: \(sha1Digest)") 

I hope this can be a ready-made link for a user like me. :)

+2
Jan 04 '17 at 2:04 on
source share

For OS X (but not iOS at the time of this writing, when 9.3.1 is current), you can use SecTransform to compute HMAC SHA-1 in Swift without a bridge header and without Objective-C. Here is an example using the first test case HMAC-SHA-1 in RFC 2202 :

 import Foundation import Security var error: Unmanaged<CFError>? let transform = SecDigestTransformCreate(kSecDigestHMACSHA1, 0, &error) let input = "Hi There" let inputData = input.dataUsingEncoding(NSUTF8StringEncoding)! let key = [UInt8](count: 20, repeatedValue: 0x0b) let keyData = key.withUnsafeBufferPointer { buffer in NSData(bytes: buffer.baseAddress, length: buffer.count) } SecTransformSetAttribute(transform, kSecTransformInputAttributeName, inputData, &error) SecTransformSetAttribute(transform, kSecDigestHMACKeyAttribute, keyData, &error) let outputData = SecTransformExecute(transform, &error) as! NSData 
+1
May 2 '16 at 1:57
source share

Thanks to Jernej Strasner for the excellent answer. Here I just update my answer for Swift 3.1:

 enum CryptoAlgorithm { case MD5, SHA1, SHA224, SHA256, SHA384, SHA512 var HMACAlgorithm: 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) } var digestLength: Int { var result: Int32 = 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: CryptoAlgorithm, key: String) -> String { let str = self.cString(using: String.Encoding.utf8) let strLen = Int(self.lengthOfBytes(using: String.Encoding.utf8)) let digestLen = algorithm.digestLength let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen) let keyStr = key.cString(using: String.Encoding.utf8) let keyLen = Int(key.lengthOfBytes(using: String.Encoding.utf8)) CCHmac(algorithm.HMACAlgorithm, keyStr!, keyLen, str!, strLen, result) let digest = stringFromResult(result: result, length: digestLen) result.deallocate(capacity: digestLen) return digest } private func stringFromResult(result: UnsafeMutablePointer<CUnsignedChar>, length: Int) -> String { let hash = NSMutableString() for i in 0..<length { hash.appendFormat("%02x", result[i]) } return String(hash) } 

And also use it:

 func sha256(StringToSign : String, secretKey : String) -> String{ let hex = StringToSign.hmac(algorithm: .SHA256, key: secretKey) let hexData = hex.data(using: String.Encoding.utf8) let finalString = hexData?.base64EncodedString(options: [.lineLength64Characters]) return finalString! } 
0
Jun 24 '17 at 13:30
source share