]> git.saurik.com Git - apple/security.git/blame - OSX/Breadcrumb/SecBreadcrumb.c
Security-58286.41.2.tar.gz
[apple/security.git] / OSX / Breadcrumb / SecBreadcrumb.c
CommitLineData
6b200bc3
A
1/*
2 * Copyright (c) 2014 - 2016 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
d8f41ccd
A
23
24#include <Security/Security.h>
25#include <Security/SecBreadcrumb.h>
26#include <Security/SecRandom.h>
27
28#include <corecrypto/ccaes.h>
29#include <corecrypto/ccpbkdf2.h>
30#include <corecrypto/ccmode.h>
31#include <corecrypto/ccmode_factory.h>
32#include <corecrypto/ccsha2.h>
33
34#include <CommonCrypto/CommonRandomSPI.h>
35
6b200bc3
A
36#import "SecCFAllocator.h"
37
d8f41ccd
A
38#define CFReleaseNull(CF) ({ __typeof__(CF) *const _pcf = &(CF), _cf = *_pcf; (_cf ? (*_pcf) = ((__typeof__(CF))0), (CFRelease(_cf), ((__typeof__(CF))0)) : _cf); })
39
40static const int kKeySize = CCAES_KEY_SIZE_128;
41static const int kSaltSize = 20;
42static const int kIterations = 5000;
43static const CFIndex tagLen = 16;
fa7225c8
A
44static const CFIndex ivLen = 16;
45static const uint8_t BCversion1 = 1;
46static const uint8_t BCversion2 = 2;
6b200bc3
A
47static const ssize_t paddingSize = 256;
48static const ssize_t maxSize = 1024;
d8f41ccd
A
49
50Boolean
51SecBreadcrumbCreateFromPassword(CFStringRef inPassword,
52 CFDataRef *outBreadcrumb,
53 CFDataRef *outEncryptedKey,
54 CFErrorRef *outError)
55{
56 const struct ccmode_ecb *ecb = ccaes_ecb_encrypt_mode();
5c19dc3a 57 const struct ccmode_gcm *gcm = ccaes_gcm_encrypt_mode();
d8f41ccd 58 const struct ccdigest_info *di = ccsha256_di();
fa7225c8 59 uint8_t iv[ivLen];
d8f41ccd
A
60 CFMutableDataRef key, npw;
61 CFDataRef pw;
62
63 *outBreadcrumb = NULL;
64 *outEncryptedKey = NULL;
65 if (outError)
66 *outError = NULL;
67
6b200bc3 68 key = CFDataCreateMutable(SecCFAllocatorZeroize(), 0);
d8f41ccd
A
69 if (key == NULL)
70 return false;
71
72 CFDataSetLength(key, kKeySize + kSaltSize + 4);
fa7225c8
A
73 if (SecRandomCopyBytes(kSecRandomDefault, CFDataGetLength(key) - 4, CFDataGetMutableBytePtr(key)) != 0) {
74 CFReleaseNull(key);
75 return false;
76 }
77 if (SecRandomCopyBytes(kSecRandomDefault, ivLen, iv) != 0) {
78 CFReleaseNull(key);
79 return false;
80 }
81
d8f41ccd
A
82 uint32_t size = htonl(kIterations);
83 memcpy(CFDataGetMutableBytePtr(key) + kKeySize + kSaltSize, &size, sizeof(size));
84
85 /*
86 * Create data for password
87 */
88
6b200bc3 89 pw = CFStringCreateExternalRepresentation(SecCFAllocatorZeroize(), inPassword, kCFStringEncodingUTF8, 0);
d8f41ccd
A
90 if (pw == NULL) {
91 CFReleaseNull(key);
92 return false;
93 }
94
95 const CFIndex passwordLength = CFDataGetLength(pw);
96
97 if (passwordLength > maxSize) {
98 CFReleaseNull(pw);
99 CFReleaseNull(key);
100 return false;
101 }
102
103 CFIndex paddedSize = passwordLength + paddingSize - (passwordLength % paddingSize);
fa7225c8 104 const CFIndex outLength = 1 + ivLen + 4 + paddedSize + tagLen;
d8f41ccd
A
105
106 npw = CFDataCreateMutable(NULL, outLength);
107 if (npw == NULL) {
108 CFReleaseNull(pw);
109 CFReleaseNull(key);
110 return false;
111 }
112 CFDataSetLength(npw, outLength);
113
114 memset(CFDataGetMutableBytePtr(npw), 0, outLength);
fa7225c8
A
115 CFDataGetMutableBytePtr(npw)[0] = BCversion2;
116 memcpy(CFDataGetMutableBytePtr(npw) + 1, iv, ivLen);
d8f41ccd 117 size = htonl(passwordLength);
fa7225c8
A
118 memcpy(CFDataGetMutableBytePtr(npw) + 1 + ivLen, &size, sizeof(size));
119 memcpy(CFDataGetMutableBytePtr(npw) + 1 + ivLen + 4, CFDataGetBytePtr(pw), passwordLength);
d8f41ccd
A
120
121 /*
122 * Now create a GCM encrypted password using the random key
123 */
124
5c19dc3a
A
125 ccgcm_ctx_decl(gcm->size, ctx);
126 ccgcm_init(gcm, ctx, kKeySize, CFDataGetMutableBytePtr(key));
fa7225c8 127 ccgcm_set_iv(gcm, ctx, ivLen, iv);
5c19dc3a 128 ccgcm_gmac(gcm, ctx, 1, CFDataGetMutableBytePtr(npw));
fa7225c8 129 ccgcm_update(gcm, ctx, outLength - tagLen - ivLen - 1, CFDataGetMutableBytePtr(npw) + 1 + ivLen, CFDataGetMutableBytePtr(npw) + 1 + ivLen);
5c19dc3a
A
130 ccgcm_finalize(gcm, ctx, tagLen, CFDataGetMutableBytePtr(npw) + outLength - tagLen);
131 ccgcm_ctx_clear(gcm->size, ctx);
d8f41ccd
A
132
133 /*
134 * Wrapping key is PBKDF2(sha256) over password
135 */
136
137 if (di->output_size < kKeySize) abort();
138
139 uint8_t rawkey[di->output_size];
140
141 if (ccpbkdf2_hmac(di, CFDataGetLength(pw), CFDataGetBytePtr(pw),
142 kSaltSize, CFDataGetMutableBytePtr(key) + kKeySize,
143 kIterations,
144 sizeof(rawkey), rawkey) != 0)
145 abort();
146
147 /*
148 * Wrap the random key with one round of ECB cryto
149 */
150
5c19dc3a
A
151 ccecb_ctx_decl(ccecb_context_size(ecb), ecbkey);
152 ccecb_init(ecb, ecbkey, kKeySize, rawkey);
153 ccecb_update(ecb, ecbkey, 1, CFDataGetMutableBytePtr(key), CFDataGetMutableBytePtr(key));
154 ccecb_ctx_clear(ccecb_context_size(ecb), ecbkey);
155
d8f41ccd
A
156 /*
157 *
158 */
159
160 memset(rawkey, 0, sizeof(rawkey));
161 CFReleaseNull(pw);
162
163 *outBreadcrumb = npw;
164 *outEncryptedKey = key;
165
166 return true;
167}
168
169
170Boolean
171SecBreadcrumbCopyPassword(CFStringRef inPassword,
172 CFDataRef inBreadcrumb,
173 CFDataRef inEncryptedKey,
174 CFStringRef *outPassword,
175 CFErrorRef *outError)
176{
177 const struct ccmode_ecb *ecb = ccaes_ecb_decrypt_mode();
d8f41ccd
A
178 const struct ccdigest_info *di = ccsha256_di();
179 CFMutableDataRef gcmkey, oldpw;
fa7225c8 180 CFIndex outLength;
d8f41ccd
A
181 CFDataRef pw;
182 uint32_t size;
183
184 *outPassword = NULL;
185 if (outError)
186 *outError = NULL;
187
188 if (CFDataGetLength(inEncryptedKey) < kKeySize + kSaltSize + 4) {
189 return false;
190 }
191
fa7225c8
A
192 if (CFDataGetBytePtr(inBreadcrumb)[0] == BCversion1) {
193 if (CFDataGetLength(inBreadcrumb) < 1 + 4 + paddingSize + tagLen)
194 return false;
195
196 outLength = CFDataGetLength(inBreadcrumb) - 1 - tagLen;
197 } else if (CFDataGetBytePtr(inBreadcrumb)[0] == BCversion2) {
198 if (CFDataGetLength(inBreadcrumb) < 1 + ivLen + 4 + paddingSize + tagLen)
199 return false;
200 outLength = CFDataGetLength(inBreadcrumb) - 1 - ivLen - tagLen;
201 } else {
d8f41ccd
A
202 return false;
203 }
204
6b200bc3 205 gcmkey = CFDataCreateMutableCopy(SecCFAllocatorZeroize(), 0, inEncryptedKey);
d8f41ccd
A
206 if (gcmkey == NULL) {
207 return false;
208 }
209
d8f41ccd
A
210 if ((outLength % 16) != 0 && outLength < 4) {
211 CFReleaseNull(gcmkey);
212 return false;
213 }
214
6b200bc3 215 oldpw = CFDataCreateMutable(SecCFAllocatorZeroize(), outLength);
d8f41ccd
A
216 if (oldpw == NULL) {
217 CFReleaseNull(gcmkey);
218 return false;
219 }
220 CFDataSetLength(oldpw, outLength);
d8f41ccd
A
221
222 /*
223 * Create data for password
224 */
225
6b200bc3 226 pw = CFStringCreateExternalRepresentation(SecCFAllocatorZeroize(), inPassword, kCFStringEncodingUTF8, 0);
d8f41ccd
A
227 if (pw == NULL) {
228 CFReleaseNull(oldpw);
229 CFReleaseNull(gcmkey);
230 return false;
231 }
232
233 /*
234 * Wrapping key is HMAC(sha256) over password
235 */
236
237 if (di->output_size < kKeySize) abort();
238
239 uint8_t rawkey[di->output_size];
240
241 memcpy(&size, CFDataGetMutableBytePtr(gcmkey) + kKeySize + kSaltSize, sizeof(size));
242 size = ntohl(size);
243
244 if (ccpbkdf2_hmac(di, CFDataGetLength(pw), CFDataGetBytePtr(pw),
245 kSaltSize, CFDataGetMutableBytePtr(gcmkey) + kKeySize,
246 size,
247 sizeof(rawkey), rawkey) != 0)
248 abort();
249
250 CFReleaseNull(pw);
251
252 /*
253 * Unwrap the random key with one round of ECB cryto
254 */
255
5c19dc3a
A
256 ccecb_ctx_decl(ccecb_context_size(ecb), ecbkey);
257 ccecb_init(ecb, ecbkey, kKeySize, rawkey);
258 ccecb_update(ecb, ecbkey, 1, CFDataGetMutableBytePtr(gcmkey), CFDataGetMutableBytePtr(gcmkey));
259 ccecb_ctx_clear(ccecb_context_size(ecb), ecbkey);
d8f41ccd
A
260 /*
261 * GCM unwrap
262 */
fa7225c8 263
d8f41ccd 264 uint8_t tag[tagLen];
fa7225c8
A
265
266 if (CFDataGetBytePtr(inBreadcrumb)[0] == BCversion1) {
267 memcpy(tag, CFDataGetBytePtr(inBreadcrumb) + 1 + outLength, tagLen);
268
269 ccgcm_one_shot_legacy(ccaes_gcm_decrypt_mode(), kKeySize, CFDataGetMutableBytePtr(gcmkey), 0, NULL, 1, CFDataGetBytePtr(inBreadcrumb),
270 outLength, CFDataGetBytePtr(inBreadcrumb) + 1, CFDataGetMutableBytePtr(oldpw), tagLen, tag);
271 if (memcmp(tag, CFDataGetBytePtr(inBreadcrumb) + 1 + outLength, tagLen) != 0) {
272 CFReleaseNull(oldpw);
6b200bc3 273 CFReleaseNull(gcmkey);
fa7225c8
A
274 return false;
275 }
276
277 } else {
278 const uint8_t *iv = CFDataGetBytePtr(inBreadcrumb) + 1;
279 int res;
280 memcpy(tag, CFDataGetBytePtr(inBreadcrumb) + 1 + ivLen + outLength, tagLen);
281
282 res = ccgcm_one_shot(ccaes_gcm_decrypt_mode(), kKeySize, CFDataGetMutableBytePtr(gcmkey),
283 ivLen, iv,
284 1, CFDataGetBytePtr(inBreadcrumb),
285 outLength, CFDataGetBytePtr(inBreadcrumb) + 1 + ivLen, CFDataGetMutableBytePtr(oldpw),
286 tagLen, tag);
287 if (res) {
866f8763 288 CFReleaseNull(gcmkey);
fa7225c8 289 CFReleaseNull(oldpw);
6b200bc3 290 CFReleaseNull(gcmkey);
fa7225c8
A
291 return false;
292 }
d8f41ccd 293 }
fa7225c8
A
294
295 CFReleaseNull(gcmkey);
d8f41ccd 296
fa7225c8 297
d8f41ccd
A
298 memcpy(&size, CFDataGetMutableBytePtr(oldpw), sizeof(size));
299 size = ntohl(size);
6b200bc3 300 if ((ssize_t) size > outLength - 4) {
d8f41ccd
A
301 CFReleaseNull(oldpw);
302 return false;
303 }
304 memmove(CFDataGetMutableBytePtr(oldpw), CFDataGetMutableBytePtr(oldpw) + 4, size);
305 CFDataSetLength(oldpw, size);
306
6b200bc3 307 *outPassword = CFStringCreateFromExternalRepresentation(SecCFAllocatorZeroize(), oldpw, kCFStringEncodingUTF8);
d8f41ccd
A
308 CFReleaseNull(oldpw);
309
310 return true;
311}
312
313CFDataRef
314SecBreadcrumbCreateNewEncryptedKey(CFStringRef oldPassword,
315 CFStringRef newPassword,
316 CFDataRef encryptedKey,
317 CFErrorRef *outError)
318{
319 const struct ccmode_ecb *enc = ccaes_ecb_encrypt_mode();
320 const struct ccmode_ecb *dec = ccaes_ecb_decrypt_mode();
321 const struct ccdigest_info *di = ccsha256_di();
322 CFMutableDataRef newEncryptedKey;
323 CFDataRef newpw = NULL, oldpw = NULL;
324 uint8_t rawkey[di->output_size];
325
326 if (CFDataGetLength(encryptedKey) < kKeySize + kSaltSize + 4) {
327 return NULL;
328 }
329
6b200bc3 330 newEncryptedKey = CFDataCreateMutableCopy(SecCFAllocatorZeroize(), 0, encryptedKey);
d8f41ccd
A
331 if (newEncryptedKey == NULL) {
332 return NULL;
333 }
334
6b200bc3 335 oldpw = CFStringCreateExternalRepresentation(SecCFAllocatorZeroize(), oldPassword, kCFStringEncodingUTF8, 0);
d8f41ccd
A
336 if (oldpw == NULL) {
337 CFReleaseNull(newEncryptedKey);
338 return false;
339 }
340
6b200bc3 341 newpw = CFStringCreateExternalRepresentation(SecCFAllocatorZeroize(), newPassword, kCFStringEncodingUTF8, 0);
d8f41ccd
A
342 if (newpw == NULL) {
343 CFReleaseNull(newEncryptedKey);
344 CFReleaseNull(oldpw);
345 return false;
346 }
347
348 if (di->output_size < kKeySize) abort();
349
350 /*
351 * Unwrap with new key
352 */
353
354 uint32_t iter;
355
356 memcpy(&iter, CFDataGetMutableBytePtr(newEncryptedKey) + kKeySize + kSaltSize, sizeof(iter));
357 iter = ntohl(iter);
358
359 if (ccpbkdf2_hmac(di, CFDataGetLength(oldpw), CFDataGetBytePtr(oldpw),
360 kSaltSize, CFDataGetMutableBytePtr(newEncryptedKey) + kKeySize,
361 iter,
362 sizeof(rawkey), rawkey) != 0)
363 abort();
364
365 CFReleaseNull(oldpw);
366
367
368 ccecb_ctx_decl(dec->size, deckey);
5c19dc3a
A
369 ccecb_init(dec, deckey, kKeySize, rawkey);
370 ccecb_update(dec, deckey, 1, CFDataGetMutableBytePtr(newEncryptedKey), CFDataGetMutableBytePtr(newEncryptedKey));
371 ccecb_ctx_clear(ccecb_context_size(dec), deckey);
d8f41ccd
A
372
373 memset(rawkey, 0, sizeof(rawkey));
374
375 /*
376 * Re-wrap with new key
377 */
378
379 if (ccpbkdf2_hmac(di, CFDataGetLength(newpw), CFDataGetBytePtr(newpw),
380 kSaltSize, CFDataGetMutableBytePtr(newEncryptedKey) + kKeySize,
381 iter,
382 sizeof(rawkey), rawkey) != 0)
383 abort();
384
385 CFReleaseNull(newpw);
386
387
388 ccecb_ctx_decl(enc->size, enckey);
5c19dc3a
A
389 ccecb_init(enc, enckey, kKeySize, rawkey);
390 ccecb_update(enc, enckey, 1, CFDataGetMutableBytePtr(newEncryptedKey), CFDataGetMutableBytePtr(newEncryptedKey));
391 ccecb_ctx_clear(ccecb_context_size(enc), enckey);
d8f41ccd
A
392
393 memset(rawkey, 0, sizeof(rawkey));
394
395 return newEncryptedKey;
396}