2 * Copyright (c) 2007-2008,2010,2012-2013 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <string.h> // memcpy
27 #include <CommonCrypto/CommonDigest.h>
28 #include <CommonCrypto/CommonDigestSPI.h>
30 #include <corecrypto/ccn.h>
32 #include "p12pbegen.h"
34 static uint8_t *concatenate_to_blocksize(const uint8_t *data
, size_t data_length
,
35 size_t blocksize
, size_t *blocklength
)
37 size_t block_length
= blocksize
* ((data_length
+ blocksize
- 1) / blocksize
);
38 uint8_t *block_ptr
, *block
;
39 block_ptr
= block
= malloc(block_length
);
42 while (block_ptr
< block
+ block_length
) {
43 size_t bytes_to_move
= block
+ block_length
- block_ptr
;
44 memcpy(block_ptr
, data
, bytes_to_move
> data_length
? data_length
: bytes_to_move
);
45 block_ptr
+= data_length
;
47 *blocklength
= block_length
;
51 int p12_pbe_gen(CFStringRef passphrase
, uint8_t *salt_ptr
, size_t salt_length
,
52 unsigned iter_count
, P12_PBE_ID pbe_id
, uint8_t *data
, size_t length
)
54 unsigned int hash_blocksize
= CC_SHA1_BLOCK_BYTES
;
55 unsigned int hash_outputsize
= CC_SHA1_DIGEST_LENGTH
;
60 /* generate diversifier block */
61 unsigned char diversifier
[hash_blocksize
];
62 memset(diversifier
, pbe_id
, sizeof(diversifier
));
64 /* convert passphrase to BE UTF16 and append double null */
65 CFDataRef passphrase_be_unicode
= CFStringCreateExternalRepresentation(kCFAllocatorDefault
, passphrase
, kCFStringEncodingUTF16BE
, '\0');
66 if (!passphrase_be_unicode
)
68 uint8_t null_termination
[2] = { 0, 0 };
69 CFMutableDataRef passphrase_be_unicode_null_term
= CFDataCreateMutableCopy(NULL
, 0, passphrase_be_unicode
);
70 CFRelease(passphrase_be_unicode
);
71 if (!passphrase_be_unicode_null_term
)
73 CFDataAppendBytes(passphrase_be_unicode_null_term
, null_termination
, sizeof(null_termination
));
75 /* generate passphrase block */
76 uint8_t *passphrase_data
= NULL
;
77 size_t passphrase_data_len
= 0;
78 size_t passphrase_length
= CFDataGetLength(passphrase_be_unicode_null_term
);
79 const unsigned char *passphrase_ptr
= CFDataGetBytePtr(passphrase_be_unicode_null_term
);
80 passphrase_data
= concatenate_to_blocksize(passphrase_ptr
, passphrase_length
, hash_blocksize
, &passphrase_data_len
);
81 CFRelease(passphrase_be_unicode_null_term
);
85 /* generate salt block */
86 uint8_t *salt_data
= NULL
;
87 size_t salt_data_len
= 0;
89 salt_data
= concatenate_to_blocksize(salt_ptr
, salt_length
, hash_blocksize
, &salt_data_len
);
91 free(passphrase_data
);
94 /* generate S||P block */
95 size_t I_length
= salt_data_len
+ passphrase_data_len
;
96 uint8_t *I_data
= malloc(I_length
);
99 free(passphrase_data
);
102 memcpy(I_data
+ 0, salt_data
, salt_data_len
);
103 memcpy(I_data
+ salt_data_len
, passphrase_data
, passphrase_data_len
);
105 free(passphrase_data
);
107 /* round up output buffer to multiple of hash block size and allocate */
108 size_t hash_output_blocks
= (length
+ hash_outputsize
- 1) / hash_outputsize
;
109 size_t temp_buf_size
= hash_output_blocks
* hash_outputsize
;
110 uint8_t *temp_buf
= malloc(temp_buf_size
);
111 uint8_t *cursor
= temp_buf
;
116 /* 64 bits cast(s): worst case here is we dont hash all the data and incorectly derive the wrong key,
117 when the passphrase + salt are over 2^32 bytes long */
118 /* loop over output in hash_output_size increments */
119 while (cursor
< temp_buf
+ temp_buf_size
) {
122 CC_SHA1_Update(&ctx
, diversifier
, (CC_LONG
)sizeof(diversifier
));
123 assert(I_length
<=UINT32_MAX
); /* debug check. Correct as long as CC_LONG is uint32_t */
124 CC_SHA1_Update(&ctx
, I_data
, (CC_LONG
)I_length
);
125 CC_SHA1_Final(cursor
, &ctx
);
127 /* run block through SHA-1 for iteration count */
129 for (i
= 1; /*first round done above*/ i
< iter_count
; i
++)
130 CCDigest(kCCDigestSHA1
, cursor
, hash_outputsize
, cursor
);
133 * b) Concatenate copies of A[i] to create a string B of
134 * length v bits (the final copy of A[i]i may be truncated
138 uint8_t *A_i
= concatenate_to_blocksize(cursor
,
139 hash_outputsize
, hash_blocksize
, &A_i_len
);
146 * c) Treating I as a concatenation I[0], I[1], ...,
147 * I[k-1] of v-bit blocks, where k = ceil(s/v) + ceil(p/v),
148 * modify I by setting I[j]=(I[j]+B+1) mod (2 ** v)
154 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
);
155 cc_unit
*tmp1
= (cc_unit
*)malloc(tmp_n
* sizeof(cc_unit
));
162 ccn_read_uint(tmp_n
, tmp1
, A_i_len
, A_i
);
163 ccn_add1(tmp_n
, tmp1
, tmp1
, 1);
167 cc_unit
*tmp2
= (cc_unit
*)malloc(tmp_n
* sizeof(cc_unit
));
175 for (j
= 0; j
< I_length
; j
+=hash_blocksize
) {
177 ccn_read_uint(tmp_n
, tmp2
, hash_blocksize
, I_data
+ j
);
179 ccn_add(tmp_n
, tmp2
, tmp2
, tmp1
);
181 /* I[j] = tempg mod 2**v
182 Just clear all the high bits above 2**v
183 In practice at most it rolled over by 1 bit, since all we did was add so
184 we should only clear one bit at most.
187 const size_t hash_blocksize_bits
= hash_blocksize
* 8;
188 while ((bitSize
= ccn_bitlen(tmp_n
, tmp2
)) > hash_blocksize_bits
)
190 ccn_set_bit(tmp2
, bitSize
- 1, 0);
193 ccn_write_uint_padded(tmp_n
, tmp2
, hash_blocksize
, I_data
+ j
);
196 cursor
+= hash_outputsize
;
202 * 7. Concatenate A[1], A[2], ..., A[c] together to form a
203 * pseudo-random bit string, A.
205 * 8. Use the first n bits of A as the output of this entire
208 memmove(data
, temp_buf
, length
);
217 //smeg => 0073006D006500670000
218 CFStringRef password
= CFSTR("smeg");
220 unsigned char salt_bytes
[] = { 0x0A, 0x58, 0xCF, 0x64, 0x53, 0x0D, 0x82, 0x3F };
221 CFDataRef salt
= CFDataCreate(NULL
, salt_bytes
, sizeof(salt_bytes
));
223 // Output KEY (length 24)
224 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 };
225 unsigned char result
[24];
226 p12PbeGen(password
, salt
, 1, PBE_ID_Key
, result
, sizeof(result
));
227 if (memcmp(correct_result
, result
, sizeof(correct_result
))) {
228 printf("test failure\n");
236 CFStringRef password
= CFSTR("queeg");
237 unsigned char salt_bytes
[] = { 0x05,0xDE,0xC9,0x59,0xAC,0xFF,0x72,0xF7 };
238 CFDataRef salt
= CFDataCreate(NULL
, salt_bytes
, sizeof(salt_bytes
));
239 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 };
240 unsigned char result
[24];
241 p12PbeGen(password
, salt
, 1000, PBE_ID_Key
, result
, sizeof(result
));
242 if (memcmp(correct_result
, result
, sizeof(correct_result
))) {
243 printf("test failure\n");
249 int main(int argc
, char *argv
[])
257 /* http://www.drh-consultancy.demon.co.uk/test.txt
265 Password (length 10):
270 Output KEY (length 24)
271 8AAAE6297B6CB04642AB5B077851284EB7128F1A2A7FBCA3
275 Password (length 10):
280 Output KEY (length 8)
285 Password (length 10):
290 Output KEY (length 24)
291 F3A95FEC48D7711E985CFE67908C5AB79FA3D7C5CAA5D966
295 Password (length 10):
300 Output KEY (length 8)
305 Password (length 10):
310 Output KEY (length 20)
311 8D967D88F6CAA9D714800AB3D48051D63F73A312
318 Password (length 12):
319 007100750065006500670000
323 Output KEY (length 24)
324 ED2034E36328830FF09DF1E1A07DD357185DAC0D4F9EB3D4
328 Password (length 12):
329 007100750065006500670000
333 Output KEY (length 8)
338 Password (length 12):
339 007100750065006500670000
343 Output KEY (length 24)
344 483DD6E919D7DE2E8E648BA8F862F3FBFBDC2BCB2C02957F
348 Password (length 12):
349 007100750065006500670000
353 Output KEY (length 8)
358 Password (length 12):
359 007100750065006500670000
363 Output KEY (length 20)
364 5EC4C7A80DF652294C3925B6489A7AB857C83476