· 7 years ago · May 26, 2018, 08:14 PM
1import Foundation
2import CommonCrypto
3
4extension Data {
5 enum Algorithm {
6 case md5
7 case sha1
8 case sha224
9 case sha256
10 case sha384
11 case sha512
12
13 var digestLength: Int {
14 switch self {
15 case .md5: return Int(CC_MD5_DIGEST_LENGTH)
16 case .sha1: return Int(CC_SHA1_DIGEST_LENGTH)
17 case .sha224: return Int(CC_SHA224_DIGEST_LENGTH)
18 case .sha256: return Int(CC_SHA256_DIGEST_LENGTH)
19 case .sha384: return Int(CC_SHA384_DIGEST_LENGTH)
20 case .sha512: return Int(CC_SHA512_DIGEST_LENGTH)
21 }
22 }
23 }
24}
25
26extension Data.Algorithm: RawRepresentable {
27 typealias RawValue = Int
28
29 init?(rawValue: Int) {
30 switch rawValue {
31 case kCCHmacAlgMD5: self = .md5
32 case kCCHmacAlgSHA1: self = .sha1
33 case kCCHmacAlgSHA224: self = .sha224
34 case kCCHmacAlgSHA256: self = .sha256
35 case kCCHmacAlgSHA384: self = .sha384
36 case kCCHmacAlgSHA512: self = .sha512
37 default: return nil
38 }
39 }
40
41 var rawValue: Int {
42 switch self {
43 case .md5: return kCCHmacAlgMD5
44 case .sha1: return kCCHmacAlgSHA1
45 case .sha224: return kCCHmacAlgSHA224
46 case .sha256: return kCCHmacAlgSHA256
47 case .sha384: return kCCHmacAlgSHA384
48 case .sha512: return kCCHmacAlgSHA512
49 }
50 }
51}
52
53extension Data {
54 func authenticationCode(for algorithm: Algorithm, secretKey: String = "") -> Data {
55 guard let secretKeyData = secretKey.data(using: .utf8) else { fatalError() }
56 return authenticationCode(for: algorithm, secretKey: secretKeyData)
57 }
58
59 func authenticationCode(for algorithm: Algorithm, secretKey: Data) -> Data {
60 let hashBytes = UnsafeMutablePointer<UInt8>.allocate(capacity: algorithm.digestLength)
61 defer { hashBytes.deallocate() }
62 withUnsafeBytes { (bytes) -> Void in
63 secretKey.withUnsafeBytes { (secretKeyBytes) -> Void in
64 CCHmac(CCHmacAlgorithm(algorithm.rawValue), secretKeyBytes, secretKey.count, bytes, count, hashBytes)
65 }
66 }
67 return Data(bytes: hashBytes, count: algorithm.digestLength)
68 }
69}