· 9 years ago · Nov 24, 2016, 02:08 PM
1Here you can see the implementation of AES I have in the current dev version of the app. Sorry I forgot the specific implementation details
2and here you can see how the system goes about generating an AES ‘payload’.
3
4[HMAC|64Bytes][IV|16Bytes][CipherText]
5
6HMAC:
7
8 func hmac(_ secretKey: Data) -> Data {
9 let mac = UnsafeMutableRawPointer.allocate(bytes: 64, alignedTo: 0) // SHA512 is 64 bytes
10 defer { mac.deallocate(bytes: 64, alignedTo: 0) }
11 CCHmac(UInt32(kCCHmacAlgSHA512), (secretKey as NSData).bytes, secretKey.count, (self as NSData).bytes, self.count, mac)
12 let ptr = mac.bindMemory(to: UInt8.self, capacity: 64)
13 let out = Data(bytes: ptr, count: 64)
14 return out
15 }
16
17
18Crypto stuff:
19
20
21 ///
22 /// Encrypts the current NSData instance using the given key, auto generates an IV and HMAC in the
23 /// following format: [HMAC|64][IV|16][CipherText|??]
24 ///
25 func aesEncrypt(_ key: Data) -> Data? {
26 // This should really be fixed.
27 /*guard key.length == Int(kCCKeySizeAES128) else {
28 print("[Crypto] Error: given key for AES Encryption operation is not of the correct expected size: \(kCCKeySizeAES128) != \(key.length)")
29 return nil
30 }*/
31 let cryptData = NSMutableData(length: Int((self.count)) + kCCBlockSizeAES128)!
32
33 let keyLength = size_t(kCCKeySizeAES128)
34 let operation: CCOperation = UInt32(kCCEncrypt)
35 let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
36 let options: CCOptions = UInt32(kCCOptionPKCS7Padding)
37
38 let iv = Data.randomData(16)
39
40 var numBytesEncrypted :size_t = 0
41
42 let cryptStatus = CCCrypt(operation,
43 algoritm,
44 options,
45 (key as NSData).bytes, keyLength,
46 (iv as NSData).bytes,
47 (self as NSData).bytes, self.count,
48 cryptData.mutableBytes, cryptData.length,
49 &numBytesEncrypted)
50
51 if UInt32(cryptStatus) == UInt32(kCCSuccess) {
52 cryptData.length = Int(numBytesEncrypted)
53 var cipherTextIV = NSData(data: iv) as Data
54 cipherTextIV.append(cryptData as Data)
55 let hmacValue = cipherTextIV.hmac(key)
56 var finalBuffer = NSData(data: hmacValue) as Data
57 finalBuffer.append(cipherTextIV)
58 return finalBuffer
59 } else {
60 print("[Crypto] Crypto error: unable to encrypt data chunk")
61 }
62 return nil
63 }
64
65 ///
66 /// Decrypts the current NSData instance using AES256 and the given key. The format of NSData should be equal to
67 /// the one generated using the encryption method above:
68 /// [HMAC|64][IV|16][CipherText|??]
69 ///
70 func aesDecrypt(_ key: Data) -> Data?
71 {
72 // This should really be fixed, but the rest of the app dosen't really adhere to this rule atm.
73 /*guard key.length == Int(kCCKeySizeAES128) else {
74 print("[Crypto] Error: given key for AES Decryption operation is not of the correct expected size: \(kCCKeySizeAES128) != \(key.length)")
75 return nil
76 }*/
77 print("\((Int(kCCKeySizeAES128))) \(Int(kCCBlockSizeAES128))")
78 print("Key len: \(key.count)")
79 let cryptData = NSMutableData(length: Int((self.count)) + kCCBlockSizeAES128)!
80 let actualData = self as NSData
81
82 let keyLength = size_t(kCCKeySizeAES128)
83 let operation: CCOperation = UInt32(kCCDecrypt)
84 let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
85 let options: CCOptions = UInt32(kCCOptionPKCS7Padding)
86
87
88 let hmacValue = actualData.subdata(with: NSMakeRange(0, 64))
89 let iv = actualData.subdata(with: NSMakeRange(64, 16))
90 let cipherText = actualData.subdata(with: NSMakeRange(80, self.count-80))
91
92 // Verify the HMAC of the data to be encrypted to prevent tampering
93 // with the cipherText before we decrypt it. It might be trying to exploit bugs in CommonCrypto
94 let verifiableData = actualData.subdata(with: NSMakeRange(64, self.count-64))
95 if (verifiableData.hmac(key) == hmacValue) == false {
96 print("[Crypto] HMAC Value on Data chunk was not correct, data has been dropped")
97 return nil
98 }
99
100 var numBytesEncrypted :size_t = 0
101
102 let cryptStatus = CCCrypt(operation,
103 algoritm,
104 options,
105 (key as NSData).bytes, keyLength,
106 (iv as NSData).bytes,
107 (cipherText as NSData).bytes, cipherText.count,
108 cryptData.mutableBytes, cryptData.length,
109 &numBytesEncrypted)
110
111 if UInt32(cryptStatus) == UInt32(kCCSuccess) {
112 cryptData.length = Int(numBytesEncrypted)
113 return cryptData as Data
114 }
115 return nil