]> git.saurik.com Git - apple/security.git/blob - sec/Security/SecOTRDHKey.c
Security-55471.14.4.tar.gz
[apple/security.git] / sec / Security / SecOTRDHKey.c
1 //
2 // SecOTRDHKey.c
3 // libsecurity_libSecOTR
4 //
5 // Created by Mitch Adler on 3/2/11.
6 // Copyright 2011 Apple Inc. All rights reserved.
7 //
8 #include "SecOTRDHKey.h"
9 #include <utilities/SecCFWrappers.h>
10
11 #include "SecOTRMath.h"
12 #include "SecOTRPacketData.h"
13
14 #include <corecrypto/ccn.h>
15 #include <corecrypto/ccsha1.h>
16 #include <corecrypto/ccec_priv.h>
17 #include <corecrypto/ccec.h>
18
19 #include <CommonCrypto/CommonRandomSPI.h>
20
21 #ifdef USECOMMONCRYPTO
22 #include <CommonCrypto/CommonDigest.h>
23 #endif
24
25 #define kECKeySize 256
26
27 struct _SecOTRFullDHKey {
28 CFRuntimeBase _base;
29
30 ccec_full_ctx_decl(ccn_sizeof(kECKeySize), _key);
31 uint8_t keyHash[CCSHA1_OUTPUT_SIZE];
32
33 };
34
35 CFGiblisFor(SecOTRFullDHKey);
36
37 static size_t AppendECPublicKeyAsDATA(CFMutableDataRef data, ccec_pub_ctx_t public_key)
38 {
39 size_t size = ccec_export_pub_size(public_key);
40
41 AppendLong(data, (uint32_t)size); /* cast: no overflow, pub size always fit in 32 bits */
42 ccec_export_pub(public_key, CFDataIncreaseLengthAndGetMutableBytes(data, (CFIndex)size));
43
44 return size;
45 }
46
47
48 static CF_RETURNS_RETAINED CFStringRef SecOTRFullDHKeyCopyDescription(CFTypeRef cf)
49 {
50 SecOTRFullDHKeyRef session = (SecOTRFullDHKeyRef)cf;
51 return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecOTRFullDHKeyRef: %p>"), session);
52 }
53
54 static void SecOTRFullDHKeyDestroy(CFTypeRef cf)
55 {
56 SecOTRFullDHKeyRef fullKey = (SecOTRFullDHKeyRef)cf;
57
58 bzero(fullKey->_key, sizeof(fullKey->_key));
59 }
60
61 SecOTRFullDHKeyRef SecOTRFullDHKCreate(CFAllocatorRef allocator)
62 {
63 SecOTRFullDHKeyRef newFDHK = CFTypeAllocate(SecOTRFullDHKey, struct _SecOTRFullDHKey, allocator);
64
65 SecFDHKNewKey(newFDHK);
66
67 return newFDHK;
68 }
69
70 SecOTRFullDHKeyRef SecOTRFullDHKCreateFromBytes(CFAllocatorRef allocator, const uint8_t**bytes, size_t*size)
71 {
72 SecOTRFullDHKeyRef newFDHK = CFTypeAllocate(SecOTRFullDHKey, struct _SecOTRFullDHKey, allocator);
73
74 ccec_ctx_init(ccec_cp_256(), newFDHK->_key);
75
76 uint32_t publicKeySize;
77 require_noerr(ReadLong(bytes, size, &publicKeySize), fail);
78
79 require(publicKeySize <= *size, fail);
80 require_noerr(ccec_import_pub(ccec_cp_256(), publicKeySize, *bytes, newFDHK->_key), fail);
81 ccdigest(ccsha1_di(), publicKeySize, *bytes, newFDHK->keyHash);
82
83 *size -= publicKeySize;
84 *bytes += publicKeySize;
85
86 require_noerr(ReadMPI(bytes, size, ccec_ctx_n(newFDHK->_key), ccec_ctx_k(newFDHK->_key)), fail);
87
88 return newFDHK;
89
90 fail:
91 CFReleaseNull(newFDHK);
92 return NULL;
93 }
94
95 void SecFDHKNewKey(SecOTRFullDHKeyRef fullKey)
96 {
97 struct ccrng_state *rng=ccDRBGGetRngState();
98
99 #if defined(CCECDH_AVAILABLE)
100 ccecdh_generate_key(ccec_cp_256(), rng, fullKey->_key);
101 #else
102 ccec_generate_key(ccec_cp_256(), rng, fullKey->_key);
103 #endif
104
105 size_t size = ccec_export_pub_size(fullKey->_key);
106 uint8_t publicKey[size];
107
108 ccec_export_pub(fullKey->_key, publicKey);
109 ccdigest(ccsha1_di(), size, publicKey, fullKey->keyHash);
110 }
111
112 void SecFDHKAppendSerialization(SecOTRFullDHKeyRef fullKey, CFMutableDataRef appendTo)
113 {
114 AppendECPublicKeyAsDATA(appendTo, fullKey->_key);
115 AppendMPI(appendTo, ccec_ctx_n(fullKey->_key), ccec_ctx_k(fullKey->_key));
116 }
117
118
119 void SecFDHKAppendPublicSerialization(SecOTRFullDHKeyRef fullKey, CFMutableDataRef appendTo)
120 {
121 if(ccec_ctx_bitlen(fullKey->_key) != kECKeySize) return;
122 AppendECPublicKeyAsDATA(appendTo, fullKey->_key);
123 }
124
125
126 uint8_t* SecFDHKGetHash(SecOTRFullDHKeyRef fullKey)
127 {
128 return fullKey->keyHash;
129 }
130
131
132
133
134 //
135 //
136 //
137 struct _SecOTRPublicDHKey {
138 CFRuntimeBase _base;
139
140 ccec_pub_ctx_decl(ccn_sizeof(kECKeySize), _key);
141 uint8_t keyHash[CCSHA1_OUTPUT_SIZE];
142
143 };
144
145 CFGiblisFor(SecOTRPublicDHKey);
146
147 static CF_RETURNS_RETAINED CFStringRef SecOTRPublicDHKeyCopyDescription(CFTypeRef cf) {
148 SecOTRPublicDHKeyRef session = (SecOTRPublicDHKeyRef)cf;
149 return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecOTRPublicDHKeyRef: %p>"), session);
150 }
151
152 static void SecOTRPublicDHKeyDestroy(CFTypeRef cf) {
153 SecOTRPublicDHKeyRef pubKey = (SecOTRPublicDHKeyRef)cf;
154 (void) pubKey;
155 }
156
157 static void ccec_copy_public(ccec_pub_ctx_t source, ccec_pub_ctx_t dest)
158 {
159 ccec_ctx_cp(dest) = ccec_ctx_cp(source);
160 // TODO: +1?!
161 ccn_set(3*ccec_ctx_n(source), (cc_unit*) ccec_ctx_point(dest)._p, (cc_unit*) ccec_ctx_point(source)._p);
162 }
163
164 SecOTRPublicDHKeyRef SecOTRPublicDHKCreateFromFullKey(CFAllocatorRef allocator, SecOTRFullDHKeyRef full)
165 {
166 SecOTRPublicDHKeyRef newPDHK = CFTypeAllocate(SecOTRPublicDHKey, struct _SecOTRPublicDHKey, allocator);
167
168 ccec_copy_public(full->_key, newPDHK->_key);
169 memcpy(newPDHK->keyHash, full->keyHash, CCSHA1_OUTPUT_SIZE);
170
171 return newPDHK;
172 }
173
174 SecOTRPublicDHKeyRef SecOTRPublicDHKCreateFromSerialization(CFAllocatorRef allocator, const uint8_t** bytes, size_t *size)
175 {
176 SecOTRPublicDHKeyRef newPDHK = CFTypeAllocate(SecOTRPublicDHKey, struct _SecOTRPublicDHKey, allocator);
177
178 uint32_t publicKeySize;
179 require_noerr(ReadLong(bytes, size, &publicKeySize), fail);
180
181 require(publicKeySize <= *size, fail);
182
183 require_noerr(ccec_import_pub(ccec_cp_256(), publicKeySize, *bytes, newPDHK->_key), fail);
184 ccdigest(ccsha1_di(), publicKeySize, *bytes, newPDHK->keyHash);
185
186 *size -= publicKeySize;
187 *bytes += publicKeySize;
188
189 return newPDHK;
190 fail:
191 CFReleaseNull(newPDHK);
192 return NULL;
193 }
194
195 SecOTRPublicDHKeyRef SecOTRPublicDHKCreateFromBytes(CFAllocatorRef allocator, const uint8_t** bytes, size_t *size)
196 {
197 SecOTRPublicDHKeyRef newPDHK = CFTypeAllocate(SecOTRPublicDHKey, struct _SecOTRPublicDHKey, allocator);
198
199 require_noerr(ccec_import_pub(ccec_cp_256(), *size, *bytes, newPDHK->_key), fail);
200 ccdigest(ccsha1_di(), *size, *bytes, newPDHK->keyHash);
201
202 return newPDHK;
203 fail:
204 CFReleaseNull(newPDHK);
205 return NULL;
206 }
207
208 void SecPDHKAppendSerialization(SecOTRPublicDHKeyRef pubKey, CFMutableDataRef appendTo)
209 {
210 AppendECPublicKeyAsDATA(appendTo, pubKey->_key);
211 }
212
213
214 uint8_t* SecPDHKGetHash(SecOTRPublicDHKeyRef pubKey)
215 {
216 return pubKey->keyHash;
217 }
218
219
220 void SecPDHKeyGenerateS(SecOTRFullDHKeyRef myKey, SecOTRPublicDHKeyRef theirKey, cc_unit* s)
221 {
222 ccn_zero(kExponentiationUnits, s);
223
224 size_t keyLen = ccn_sizeof_n(kExponentiationUnits);
225 ccec_compute_key(myKey->_key, theirKey->_key, &keyLen, (uint8_t*)s);
226 }
227
228 static int ccec_cmp(ccec_pub_ctx_t l, ccec_pub_ctx_t r)
229 {
230 size_t lsize = ccec_export_pub_size(l);
231 size_t rsize = ccec_export_pub_size(r);
232
233 int result = 0;
234
235 if (lsize == rsize) {
236 uint8_t lpub[lsize];
237 uint8_t rpub[rsize];
238
239 ccec_export_pub(l, lpub);
240 ccec_export_pub(r, rpub);
241
242 result = memcmp(lpub, rpub, lsize);
243 } else {
244 result = rsize < lsize ? -1 : 1;
245 }
246
247 return result;
248 }
249
250 bool SecDHKIsGreater(SecOTRFullDHKeyRef myKey, SecOTRPublicDHKeyRef theirKey)
251 {
252 return ccec_cmp(myKey->_key, theirKey->_key) > 0;
253 }
254
255 static void DeriveKeys(CFDataRef dataToHash,
256 uint8_t* messageKey,
257 uint8_t* macKey)
258 {
259 if (messageKey == NULL && macKey == NULL)
260 return;
261
262 uint8_t hashedSharedKey[CCSHA1_OUTPUT_SIZE];
263
264 #ifdef USECOMMONCRYPTO
265 (void) CCDigest(kCCDigestSHA1, CFDataGetBytePtr(dataToHash), (uint32_t)CFDataGetLength(dataToHash), hashedSharedKey);
266 #else
267 ccdigest(ccsha1_di(), CFDataGetLength(dataToHash), CFDataGetBytePtr(dataToHash), hashedSharedKey);
268 #endif
269
270 if (messageKey)
271 memcpy(messageKey, hashedSharedKey, kOTRMessageKeyBytes);
272
273 if (macKey) {
274 #ifdef USECOMMONCRYPTO
275 (void) CCDigest(kCCDigestSHA1, messageKey, kOTRMessageKeyBytes, macKey);
276 #else
277 ccdigest(ccsha1_di(), kOTRMessageKeyBytes, messageKey, macKey);
278 #endif
279 }
280
281 bzero(hashedSharedKey, sizeof(hashedSharedKey));
282 }
283
284 void SecOTRDHKGenerateOTRKeys(SecOTRFullDHKeyRef myKey, SecOTRPublicDHKeyRef theirKey,
285 uint8_t* sendMessageKey, uint8_t* sendMacKey,
286 uint8_t* receiveMessageKey, uint8_t* receiveMacKey)
287 {
288 CFMutableDataRef dataToHash = CFDataCreateMutable(kCFAllocatorDefault, 0);
289
290 {
291 cc_unit s[kExponentiationUnits];
292
293 SecPDHKeyGenerateS(myKey, theirKey, s);
294 AppendByte(dataToHash, SecDHKIsGreater(myKey, theirKey) ? 0x01 : 0x02);
295 AppendMPI(dataToHash, kExponentiationUnits, s);
296
297 ccn_zero(kExponentiationUnits, s);
298 }
299
300 DeriveKeys(dataToHash, receiveMessageKey, receiveMacKey);
301
302 uint8_t *messageTypeByte = CFDataGetMutableBytePtr(dataToHash);
303
304 *messageTypeByte ^= 0x03; // Invert the bits since it's either 1 or 2.
305
306 DeriveKeys(dataToHash, sendMessageKey, sendMacKey);
307
308 CFReleaseNull(dataToHash);
309 }