Last active
December 4, 2019 04:51
-
-
Save MihaelIsaev/f913d84b918d2b2c067d to your computer and use it in GitHub Desktop.
Easy to use Swift implementation of CommonCrypto HMAC. You can easily hash your String to: md5, sha1, sha224, sha256, sha384, sha512 with pure Swift.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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. | |
// | |
// *********************************************************** | |
// | |
import Foundation | |
import CommonCrypto | |
extension String { | |
var md5: String { | |
return HMAC.hash(self, algo: HMACAlgo.MD5) | |
} | |
var sha1: String { | |
return HMAC.hash(self, algo: HMACAlgo.SHA1) | |
} | |
var sha224: String { | |
return HMAC.hash(self, algo: HMACAlgo.SHA224) | |
} | |
var sha256: String { | |
return HMAC.hash(self, algo: HMACAlgo.SHA256) | |
} | |
var sha384: String { | |
return HMAC.hash(self, algo: HMACAlgo.SHA384) | |
} | |
var sha512: String { | |
return HMAC.hash(self, algo: HMACAlgo.SHA512) | |
} | |
} | |
public struct HMAC { | |
static func hash(inp: String, algo: HMACAlgo) -> String { | |
if let stringData = inp.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) { | |
return hexStringFromData(digest(stringData, algo: algo)) | |
} | |
return "" | |
} | |
private static func digest(input : NSData, algo: HMACAlgo) -> NSData { | |
let digestLength = algo.digestLength() | |
var hash = [UInt8](count: digestLength, repeatedValue: 0) | |
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](count: input.length, repeatedValue: 0) | |
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) | |
} | |
} |
@idmean yes, but the API is pure Swift at least.
Please adjust your tagline, this is not pure Swift.
this is not hmac but just the hashing functions CCHmac
is the correct C function to call
Maybe this is useful for you:
http://stackoverflow.com/questions/25248598/importing-commoncrypto-in-a-swift-framework
Updated for Swift 4 here: https://gist.github.com/commscheck/76d23e4af3c4e3fbec7c31ce57795835
Full tutorial with example project in xcode 9 and swift 4: https://nabtron.com/commoncrypto-hmac-swift/
Swift 4.2:
import Foundation
import CommonCrypto
extension String {
var md5: String {
return HMAC.hash(self, algo: .MD5)
}
var sha1: String {
return HMAC.hash(self, algo: .SHA1)
}
var sha224: String {
return HMAC.hash(self, algo: .SHA224)
}
var sha256: String {
return HMAC.hash(self, algo: .SHA256)
}
var sha384: String {
return HMAC.hash(self, algo: .SHA384)
}
var sha512: String {
return HMAC.hash(self, algo: .SHA512)
}
}
private struct HMAC {
static func hash(_ inp: String, algo: HMACAlgo) -> String {
if let stringData = inp.data(using: .utf8, allowLossyConversion: false) {
return hexStringFromData(digest(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)
case .SHA1: CC_SHA1(input.bytes, UInt32(input.length), &hash)
case .SHA224: CC_SHA224(input.bytes, UInt32(input.length), &hash)
case .SHA256: CC_SHA256(input.bytes, UInt32(input.length), &hash)
case .SHA384: CC_SHA384(input.bytes, UInt32(input.length), &hash)
case .SHA512: CC_SHA512(input.bytes, UInt32(input.length), &hash)
}
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
}
}
private 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)
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is not pure Swift. You are calling C and Foundation APIs.