]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/p12pbegen.c
Security-59754.41.1.tar.gz
[apple/security.git] / OSX / sec / Security / p12pbegen.c
1 /*
2 * Copyright (c) 2007-2008,2010,2012-2013 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 */
23
24 #include <stdlib.h>
25 #include <string.h> // memcpy
26
27 #include <CommonCrypto/CommonDigest.h>
28 #include <CommonCrypto/CommonDigestSPI.h>
29
30 #include <corecrypto/ccn.h>
31
32 #include "p12pbegen.h"
33
34 #include <security_utilities/simulatecrash_assert.h>
35
36 static uint8_t *concatenate_to_blocksize(const uint8_t *data, size_t data_length,
37 size_t blocksize, size_t *blocklength)
38 {
39 size_t block_length = blocksize * ((data_length + blocksize - 1) / blocksize);
40 uint8_t *block_ptr, *block;
41 block_ptr = block = malloc(block_length);
42 if (!block_ptr)
43 return NULL;
44 while (block_ptr < block + block_length) {
45 size_t bytes_to_move = block + block_length - block_ptr;
46 memcpy(block_ptr, data, bytes_to_move > data_length ? data_length : bytes_to_move);
47 block_ptr += data_length;
48 }
49 *blocklength = block_length;
50 return block;
51 }
52
53 int p12_pbe_gen(CFStringRef passphrase, uint8_t *salt_ptr, size_t salt_length,
54 unsigned iter_count, P12_PBE_ID pbe_id, uint8_t *data, size_t length)
55 {
56 unsigned int hash_blocksize = CC_SHA1_BLOCK_BYTES;
57 unsigned int hash_outputsize = CC_SHA1_DIGEST_LENGTH;
58
59 if (!passphrase)
60 return -1;
61
62 /* generate diversifier block */
63 unsigned char diversifier[hash_blocksize];
64 memset(diversifier, pbe_id, sizeof(diversifier));
65
66 /* convert passphrase to BE UTF16 and append double null */
67 CFDataRef passphrase_be_unicode = CFStringCreateExternalRepresentation(kCFAllocatorDefault, passphrase, kCFStringEncodingUTF16BE, '\0');
68 if (!passphrase_be_unicode)
69 return -1;
70 uint8_t null_termination[2] = { 0, 0 };
71 CFMutableDataRef passphrase_be_unicode_null_term = CFDataCreateMutableCopy(NULL, 0, passphrase_be_unicode);
72 CFRelease(passphrase_be_unicode);
73 if (!passphrase_be_unicode_null_term)
74 return -1;
75 CFDataAppendBytes(passphrase_be_unicode_null_term, null_termination, sizeof(null_termination));
76
77 /* generate passphrase block */
78 uint8_t *passphrase_data = NULL;
79 size_t passphrase_data_len = 0;
80 size_t passphrase_length = CFDataGetLength(passphrase_be_unicode_null_term);
81 const unsigned char *passphrase_ptr = CFDataGetBytePtr(passphrase_be_unicode_null_term);
82 passphrase_data = concatenate_to_blocksize(passphrase_ptr, passphrase_length, hash_blocksize, &passphrase_data_len);
83 CFRelease(passphrase_be_unicode_null_term);
84 if (!passphrase_data)
85 return -1;
86
87 /* generate salt block */
88 uint8_t *salt_data = NULL;
89 size_t salt_data_len = 0;
90 if (salt_length)
91 salt_data = concatenate_to_blocksize(salt_ptr, salt_length, hash_blocksize, &salt_data_len);
92 if (!salt_data){
93 free(passphrase_data);
94 return -1;
95 }
96 /* generate S||P block */
97 size_t I_length = salt_data_len + passphrase_data_len;
98 uint8_t *I_data = malloc(I_length);
99 if (!I_data){
100 free(salt_data);
101 free(passphrase_data);
102 return -1;
103 }
104 memcpy(I_data + 0, salt_data, salt_data_len);
105 memcpy(I_data + salt_data_len, passphrase_data, passphrase_data_len);
106 free(salt_data);
107 free(passphrase_data);
108
109 /* round up output buffer to multiple of hash block size and allocate */
110 size_t hash_output_blocks = (length + hash_outputsize - 1) / hash_outputsize;
111 size_t temp_buf_size = hash_output_blocks * hash_outputsize;
112 uint8_t *temp_buf = malloc(temp_buf_size);
113 uint8_t *cursor = temp_buf;
114 if (!temp_buf){
115 free(I_data);
116 return -1;
117 }
118 /* 64 bits cast(s): worst case here is we dont hash all the data and incorectly derive the wrong key,
119 when the passphrase + salt are over 2^32 bytes long */
120 /* loop over output in hash_output_size increments */
121 while (cursor < temp_buf + temp_buf_size) {
122 CC_SHA1_CTX ctx;
123 CC_SHA1_Init(&ctx);
124 CC_SHA1_Update(&ctx, diversifier, (CC_LONG)sizeof(diversifier));
125 assert(I_length<=UINT32_MAX); /* debug check. Correct as long as CC_LONG is uint32_t */
126 CC_SHA1_Update(&ctx, I_data, (CC_LONG)I_length);
127 CC_SHA1_Final(cursor, &ctx);
128
129 /* run block through SHA-1 for iteration count */
130 unsigned int i;
131 for (i = 1; /*first round done above*/ i < iter_count; i++)
132 CCDigest(kCCDigestSHA1, cursor, hash_outputsize, cursor);
133
134 /*
135 * b) Concatenate copies of A[i] to create a string B of
136 * length v bits (the final copy of A[i]i may be truncated
137 * to create B).
138 */
139 size_t A_i_len = 0;
140 uint8_t *A_i = concatenate_to_blocksize(cursor,
141 hash_outputsize, hash_blocksize, &A_i_len);
142 if (!A_i){
143 free(I_data);
144 free(temp_buf);
145 return -1;
146 }
147 /*
148 * c) Treating I as a concatenation I[0], I[1], ...,
149 * I[k-1] of v-bit blocks, where k = ceil(s/v) + ceil(p/v),
150 * modify I by setting I[j]=(I[j]+B+1) mod (2 ** v)
151 * for each j.
152 */
153
154 /* tmp1 = B+1 */
155
156 const cc_size tmp_n = ccn_nof_size(A_i_len + 1) > ccn_nof_size(hash_blocksize) ? ccn_nof_size(A_i_len + 1) : ccn_nof_size(hash_blocksize);
157 cc_unit *tmp1 = (cc_unit *)malloc(tmp_n * sizeof(cc_unit));
158 if (!tmp1) {
159 free(A_i);
160 free(I_data);
161 free(temp_buf);
162 return -1;
163 }
164 ccn_read_uint(tmp_n, tmp1, A_i_len, A_i);
165 ccn_add1(tmp_n, tmp1, tmp1, 1);
166
167 free(A_i);
168
169 cc_unit *tmp2 = (cc_unit *)malloc(tmp_n * sizeof(cc_unit));
170 if (!tmp2) {
171 free(I_data);
172 free(temp_buf);
173 free(tmp1);
174 return -1;
175 }
176 unsigned int j;
177 for (j = 0; j < I_length; j+=hash_blocksize) {
178 /* tempg = I[j]; */
179 ccn_read_uint(tmp_n, tmp2, hash_blocksize, I_data + j);
180 /* tempg += tmp1 */
181 ccn_add(tmp_n, tmp2, tmp2, tmp1);
182
183 /* I[j] = tempg mod 2**v
184 Just clear all the high bits above 2**v
185 In practice at most it rolled over by 1 bit, since all we did was add so
186 we should only clear one bit at most.
187 */
188 size_t bitSize;
189 const size_t hash_blocksize_bits = hash_blocksize * 8;
190 while ((bitSize = ccn_bitlen(tmp_n, tmp2)) > hash_blocksize_bits)
191 {
192 ccn_set_bit(tmp2, bitSize - 1, 0);
193 }
194
195 ccn_write_uint_padded(tmp_n, tmp2, hash_blocksize, I_data + j);
196 }
197
198 cursor += hash_outputsize;
199 free(tmp1);
200 free(tmp2);
201 }
202
203 /*
204 * 7. Concatenate A[1], A[2], ..., A[c] together to form a
205 * pseudo-random bit string, A.
206 *
207 * 8. Use the first n bits of A as the output of this entire
208 * process.
209 */
210 memmove(data, temp_buf, length);
211 free(temp_buf);
212 free(I_data);
213 return 0;
214 }
215
216 #if 0
217 bool test()
218 {
219 //smeg => 0073006D006500670000
220 CFStringRef password = CFSTR("smeg");
221 //Salt (length 8):
222 unsigned char salt_bytes[] = { 0x0A, 0x58, 0xCF, 0x64, 0x53, 0x0D, 0x82, 0x3F };
223 CFDataRef salt = CFDataCreate(NULL, salt_bytes, sizeof(salt_bytes));
224 // ID 1, ITER 1
225 // Output KEY (length 24)
226 unsigned char correct_result[] = { 0x8A, 0xAA, 0xE6, 0x29, 0x7B, 0x6C, 0xB0, 0x46, 0x42, 0xAB, 0x5B, 0x07, 0x78, 0x51, 0x28, 0x4E, 0xB7, 0x12, 0x8F, 0x1A, 0x2A, 0x7F, 0xBC, 0xA3 };
227 unsigned char result[24];
228 p12PbeGen(password, salt, 1, PBE_ID_Key, result, sizeof(result));
229 if (memcmp(correct_result, result, sizeof(correct_result))) {
230 printf("test failure\n");
231 return false;
232 }
233 return true;
234 }
235
236 bool test2()
237 {
238 CFStringRef password = CFSTR("queeg");
239 unsigned char salt_bytes[] = { 0x05,0xDE,0xC9,0x59,0xAC,0xFF,0x72,0xF7 };
240 CFDataRef salt = CFDataCreate(NULL, salt_bytes, sizeof(salt_bytes));
241 unsigned char correct_result[] = { 0xED,0x20,0x34,0xE3,0x63,0x28,0x83,0x0F,0xF0,0x9D,0xF1,0xE1,0xA0,0x7D,0xD3,0x57,0x18,0x5D,0xAC,0x0D,0x4F,0x9E,0xB3,0xD4 };
242 unsigned char result[24];
243 p12PbeGen(password, salt, 1000, PBE_ID_Key, result, sizeof(result));
244 if (memcmp(correct_result, result, sizeof(correct_result))) {
245 printf("test failure\n");
246 return false;
247 }
248 return true;
249 }
250
251 int main(int argc, char *argv[])
252 {
253 test();
254 test2();
255 }
256
257 #endif
258
259 /* http://www.drh-consultancy.demon.co.uk/test.txt
260
261 Test Vectors set 1.
262
263 Password: smeg
264
265 KEYGEN DEBUG
266 ID 1, ITER 1
267 Password (length 10):
268 0073006D006500670000
269 Salt (length 8):
270 0A58CF64530D823F
271 ID 1, ITER 1
272 Output KEY (length 24)
273 8AAAE6297B6CB04642AB5B077851284EB7128F1A2A7FBCA3
274
275 KEYGEN DEBUG
276 ID 2, ITER 1
277 Password (length 10):
278 0073006D006500670000
279 Salt (length 8):
280 0A58CF64530D823F
281 ID 2, ITER 1
282 Output KEY (length 8)
283 79993DFE048D3B76
284
285 KEYGEN DEBUG
286 ID 1, ITER 1
287 Password (length 10):
288 0073006D006500670000
289 Salt (length 8):
290 642B99AB44FB4B1F
291 ID 1, ITER 1
292 Output KEY (length 24)
293 F3A95FEC48D7711E985CFE67908C5AB79FA3D7C5CAA5D966
294
295 KEYGEN DEBUG
296 ID 2, ITER 1
297 Password (length 10):
298 0073006D006500670000
299 Salt (length 8):
300 642B99AB44FB4B1F
301 ID 2, ITER 1
302 Output KEY (length 8)
303 C0A38D64A79BEA1D
304
305 KEYGEN DEBUG
306 ID 3, ITER 1
307 Password (length 10):
308 0073006D006500670000
309 Salt (length 8):
310 3D83C0E4546AC140
311 ID 3, ITER 1
312 Output KEY (length 20)
313 8D967D88F6CAA9D714800AB3D48051D63F73A312
314
315 Test Vectors set 2.
316 Password: queeg
317
318 KEYGEN DEBUG
319 ID 1, ITER 1000
320 Password (length 12):
321 007100750065006500670000
322 Salt (length 8):
323 05DEC959ACFF72F7
324 ID 1, ITER 1000
325 Output KEY (length 24)
326 ED2034E36328830FF09DF1E1A07DD357185DAC0D4F9EB3D4
327
328 KEYGEN DEBUG
329 ID 2, ITER 1000
330 Password (length 12):
331 007100750065006500670000
332 Salt (length 8):
333 05DEC959ACFF72F7
334 ID 2, ITER 1000
335 Output KEY (length 8)
336 11DEDAD7758D4860
337
338 KEYGEN DEBUG
339 ID 1, ITER 1000
340 Password (length 12):
341 007100750065006500670000
342 Salt (length 8):
343 1682C0FC5B3F7EC5
344 ID 1, ITER 1000
345 Output KEY (length 24)
346 483DD6E919D7DE2E8E648BA8F862F3FBFBDC2BCB2C02957F
347
348 KEYGEN DEBUG
349 ID 2, ITER 1000
350 Password (length 12):
351 007100750065006500670000
352 Salt (length 8):
353 1682C0FC5B3F7EC5
354 ID 2, ITER 1000
355 Output KEY (length 8)
356 9D461D1B00355C50
357
358 KEYGEN DEBUG
359 ID 3, ITER 1000
360 Password (length 12):
361 007100750065006500670000
362 Salt (length 8):
363 263216FCC2FAB31C
364 ID 3, ITER 1000
365 Output KEY (length 20)
366 5EC4C7A80DF652294C3925B6489A7AB857C83476
367 */
368