]> git.saurik.com Git - apple/xnu.git/blob - osfmk/corecrypto/ccdbrg/src/ccdrbg_nisthmac.c
xnu-3789.1.32.tar.gz
[apple/xnu.git] / osfmk / corecrypto / ccdbrg / src / ccdrbg_nisthmac.c
1 /*
2 * ccdrbg_nisthmac.c
3 * corecrypto
4 *
5 * Created on 05/09/2014
6 *
7 * Copyright (c) 2014,2015 Apple Inc. All rights reserved.
8 *
9 */
10
11 #include <corecrypto/ccdrbg.h>
12 #include <corecrypto/cchmac.h>
13 #include <corecrypto/ccsha2.h>
14 #include <corecrypto/cc_priv.h>
15 #include <corecrypto/cc_debug.h>
16 #include <corecrypto/cc_macros.h>
17
18 // Test vectors at:
19 // http://csrc.nist.gov/groups/STM/cavp/#05
20 // http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip
21 //
22
23 /*
24 This HMAC DBRG is described in:
25
26 SP 800-90 A Rev. 1 (2nd Draft)
27 DRAFT Recommendation for Random Number Generation Using Deterministic Random Bit Generators
28 April 2014
29
30
31 See in particular
32 - 10.1.2 HMAC_DRBG (p 45)
33 - B.2 HMAC_DRBGExample (p 83)
34
35 We support maximum security strength of 256 bits
36 Note that the example in B.2 is very limited, refer to §10.1.2 for more
37 */
38
39 /*
40 The Get_entropy_input function is specified in pseudocode in [SP 800-90C] for various RBG constructions;
41 however, in general, the function has the following meaning:
42 Get_entropy_input: A function that is used to obtain entropy input. The function call is:
43 (status, entropy_input) = Get_entropy_input (min_entropy, min_ length, max_ length, prediction_resistance_request),
44 which requests a string of bits (entropy_input) with at least min_entropy bits of entropy. The length for the string
45 shall be equal to or greater than min_length bits, and less than or equal to max_length bits. The
46 prediction_resistance_request parameter indicates whether or not prediction resistance is to be provided during the request
47 (i.e., whether fresh entropy is required). A status code is also returned from the function.
48 */
49
50 /*
51 Check the validity of the input parameters.
52 1. If (requested_instantiation_security_strength > 256), then Return (“Invalid
53 requested_instantiation_security_strength”, −1).
54 2. If (len (personalization_string) > 160), then Return (“Personalization_string
55 too long”, −1)
56 Comment: Set the security_strength to one of the valid security strengths.
57 3. If (requested_security_strength ≤ 112), then security_strength = 112 Else (requested_ security_strength ≤ 128), then security_strength = 128 Else (requested_ security_strength ≤ 192), then security_strength = 192 Else security_strength = 256.
58 Comment: Get the entropy_input and the nonce.
59 4. min_entropy = 1.5 × security_strength.
60 5. (status, entropy_input) = Get_entropy_input (min_entropy, 1000).
61 6. If (status ≠ “Success”), then Return (status, −1).
62 */
63
64 /*
65 1. highest_supported_security_strength = 256.
66 2. Output block (outlen) = 256 bits.
67 3. Required minimum entropy for the entropy input at instantiation = 3/2 security_strength (this includes the entropy required for the nonce).
68 4. Seed length (seedlen) = 440 bits.
69 5. Maximum number of bits per request (max_number_of_bits_per_request) = 7500
70 bits.
71 6. Reseed_interval (reseed_ interval) = 10,000 requests.
72 7. Maximum length of the personalization string (max_personalization_string_length) = 160 bits.
73 8. Maximum length of the entropy input (max _length) = 1000 bits.
74 */
75
76 //
77 // Defines below based on 10.1, Table 2: Definitions for Hash-Based DRBG Mechanisms (p 39)
78 //
79
80 #define NH_MAX_OUTPUT_BLOCK_SIZE (CCSHA512_OUTPUT_SIZE) // 512 bits, i.e. 64 bytes (CCSHA512_OUTPUT_SIZE)
81 #define NH_MAX_KEY_SIZE (CCSHA512_OUTPUT_SIZE) // 512 bits, i.e. 64 bytes (CCSHA512_OUTPUT_SIZE)
82
83 #define MIN_REQ_ENTROPY(di) ((di)->output_size/2)
84
85 struct ccdrbg_nisthmac_state {
86 const struct ccdrbg_nisthmac_custom *custom; //ccdrbg_nisthmac_state does not need to store ccdrbg_info. ccdrbg_nisthmac_custom is sufficient
87 size_t bytesLeft;
88 uint64_t reseed_counter; // the reseed counter should be able to hole 2^^48. size_t might be smaller than 48 bits
89 size_t vsize;
90 size_t keysize;
91 uint8_t v[2*NH_MAX_OUTPUT_BLOCK_SIZE];
92 uint8_t *vptr;
93 uint8_t *nextvptr;
94 uint8_t key[NH_MAX_KEY_SIZE];
95 };
96
97 #define DRBG_NISTHMAC_DEBUG 0
98
99
100 #if DRBG_NISTHMAC_DEBUG
101 static void dumpState(const char *label, struct ccdrbg_nisthmac_state *state) {
102 //cc_print(label, state->vsize, state->nextvptr);
103 cc_print(label, state->vsize, state->vptr);
104 cc_print(label, state->keysize, state->key);
105 }
106 #endif
107
108
109 static void done(struct ccdrbg_state *drbg);
110
111 /*
112 NIST SP 800-90A, Rev. 1 HMAC_DRBG April 2014, p 46
113
114 HMAC_DRBG_Update (provided_data, K, V):
115 1. provided_data: The data to be used.
116 2. K: The current value of Key.
117 3. V: The current value of V.
118 Output:
119 1. K: The new value for Key.
120 2. V: The new value for V.
121
122 HMAC_DRBG Update Process:
123
124 1. K = HMAC (K, V || 0x00 || provided_data).
125 2. V=HMAC(K,V).
126 3. If (provided_data = Null), then return K and V.
127 4. K = HMAC (K, V || 0x01 || provided_data).
128 5. V=HMAC(K,V).
129 6. Return K and V.
130 */
131
132 // was: size_t providedDataLength, const void *providedData
133
134 /*
135 To handle the case where we have three strings that are concatenated,
136 we pass in three (ptr, len) pairs
137 */
138
139 static int hmac_dbrg_update(struct ccdrbg_state *drbg,
140 size_t daLen, const void *da,
141 size_t dbLen, const void *db,
142 size_t dcLen, const void *dc
143 )
144 {
145 int rc=CCDRBG_STATUS_ERROR;
146 struct ccdrbg_nisthmac_state *state = (struct ccdrbg_nisthmac_state *)drbg;
147 const struct ccdigest_info *di = state->custom->di;
148
149 const unsigned char cZero = 0x00;
150 const unsigned char cOne = 0x01;
151
152 cchmac_ctx_decl(di->state_size, di->block_size, ctx);
153 cchmac_init(di, ctx, state->keysize, state->key);
154
155 // 1. K = HMAC (K, V || 0x00 || provided_data).
156 cchmac_update(di, ctx, state->vsize, state->vptr);
157 cchmac_update(di, ctx, 1, &cZero);
158 if (da && daLen) cchmac_update(di, ctx, daLen, da);
159 if (db && dbLen) cchmac_update(di, ctx, dbLen, db);
160 if (dc && dcLen) cchmac_update(di, ctx, dcLen, dc);
161 cchmac_final(di, ctx, state->key);
162
163 // One parameter must be non-empty, or return
164 if (((da && daLen) || (db && dbLen) || (dc && dcLen))) {
165 // 2. V=HMAC(K,V).
166 cchmac(di, state->keysize, state->key, state->vsize, state->vptr, state->vptr);
167 // 4. K = HMAC (K, V || 0x01 || provided_data).
168 cchmac_init(di, ctx, state->keysize, state->key);
169 cchmac_update(di, ctx, state->vsize, state->vptr);
170 cchmac_update(di, ctx, 1, &cOne);
171 if (da && daLen) cchmac_update(di, ctx, daLen, da);
172 if (db && dbLen) cchmac_update(di, ctx, dbLen, db);
173 if (dc && dcLen) cchmac_update(di, ctx, dcLen, dc);
174 cchmac_final(di, ctx, state->key);
175 }
176 // If additional data 5. V=HMAC(K,V)
177 // If no addtional data, this is step 2. V=HMAC(K,V).
178 state->bytesLeft = 0;
179
180 // FIPS 140-2 4.9.2 Conditional Tests
181 // "the first n-bit block generated after power-up, initialization, or reset shall not be used, but shall be saved for comparison with the next n-bit block to be generated"
182 // Generate the first block and the second block. Compare for FIPS and discard the first block
183 // We keep the second block as the first set of data to be returned
184 cchmac(di, state->keysize, state->key, state->vsize, state->vptr, state->vptr); // First block
185 cchmac(di, state->keysize, state->key, state->vsize, state->vptr, state->nextvptr); // First to be returned
186 if (0==cc_cmp_safe(state->vsize, state->vptr, state->nextvptr)) {
187 //The world as we know it has come to an end
188 //the DRBG data structure is zeroized. subsequent calls to
189 //DRBG ends up in NULL dereferencing and/or unpredictable state.
190 //catastrophic error in SP 800-90A
191 done(drbg);
192 rc=CCDRBG_STATUS_ABORT;
193 cc_abort(NULL);
194 goto errOut;
195 }
196 rc=CCDRBG_STATUS_OK;
197 errOut:
198 return rc;
199 }
200
201 //make sure state is initialized, before calling this function
202 static int validate_inputs(struct ccdrbg_nisthmac_state *state,
203 size_t entropyLength,
204 size_t additionalInputLength,
205 size_t psLength)
206 {
207 int rc;
208 const struct ccdrbg_nisthmac_custom *custom=state->custom;
209 const struct ccdigest_info *di = custom->di;
210
211 rc =CCDRBG_STATUS_ERROR;
212 //buffer size checks
213 cc_require (di->output_size<=sizeof(state->v)/2, end); //digest size too long
214 cc_require (di->output_size<=sizeof(state->key), end); //digest size too long
215
216 //NIST SP800 compliance checks
217 //the following maximum checks are redundant if long is 32 bits.
218
219 rc=CCDRBG_STATUS_PARAM_ERROR;
220 cc_require (psLength <= CCDRBG_MAX_PSINPUT_SIZE, end); //personalization string too long
221 cc_require (entropyLength <= CCDRBG_MAX_ENTROPY_SIZE, end); //supplied too much entropy
222 cc_require (additionalInputLength <= CCDRBG_MAX_ADDITIONALINPUT_SIZE, end); //additional input too long
223 cc_require (entropyLength >= MIN_REQ_ENTROPY(di), end); //supplied too litle entropy
224
225 cc_require(di->output_size<=NH_MAX_OUTPUT_BLOCK_SIZE, end); //the requested security strength is not supported
226
227 rc=CCDRBG_STATUS_OK;
228 end:
229 return rc;
230 }
231
232 /*
233 NIST SP 800-90A, Rev. 1 April 2014 B.2.2, p 84
234
235 HMAC_DRBG_Instantiate_algorithm (...):
236 Input: bitstring (entropy_input, personalization_string).
237 Output: bitstring (V, Key), integer reseed_counter.
238
239 Process:
240 1. seed_material = entropy_input || personalization_string.
241 2. Set Key to outlen bits of zeros.
242 3. Set V to outlen/8 bytes of 0x01.
243 4. (Key, V) = HMAC_DRBG_Update (seed_material, Key, V).
244 5. reseed_counter = 1.
245 6. Return (V, Key, reseed_counter).
246 */
247
248 // This version does not do memory allocation
249 //SP800-90 A: Required minimum entropy for instantiate and reseed=security_strength
250
251 static int hmac_dbrg_instantiate_algorithm(struct ccdrbg_state *drbg,
252 size_t entropyLength, const void *entropy,
253 size_t nonceLength, const void *nonce,
254 size_t psLength, const void *ps)
255 {
256 // TODO: The NIST code passes nonce (i.e. HMAC key) to generate, but cc interface isn't set up that way
257 struct ccdrbg_nisthmac_state *state = (struct ccdrbg_nisthmac_state *)drbg;
258
259 // 1. seed_material = entropy_input || nonce || personalization_string.
260
261 // 2. Set Key to outlen bits of zeros.
262 cc_zero(state->keysize, state->key);
263
264 // 3. Set V to outlen/8 bytes of 0x01.
265 CC_MEMSET(state->vptr, 0x01, state->vsize);
266
267 // 4. (Key, V) = HMAC_DRBG_Update (seed_material, Key, V).
268 hmac_dbrg_update(drbg, entropyLength, entropy, nonceLength, nonce, psLength, ps);
269
270 // 5. reseed_counter = 1.
271 state->reseed_counter = 1;
272
273 return CCDRBG_STATUS_OK;
274 }
275
276 // In NIST terminology, the nonce is the HMAC key and ps is the personalization string
277 // We assume that the caller has passed in
278 // min_entropy = NH_REQUIRED_MIN_ENTROPY(security_strength)
279 // bytes of entropy
280
281 static int init(const struct ccdrbg_info *info, struct ccdrbg_state *drbg,
282 size_t entropyLength, const void* entropy,
283 size_t nonceLength, const void* nonce,
284 size_t psLength, const void* ps)
285 {
286 struct ccdrbg_nisthmac_state *state=(struct ccdrbg_nisthmac_state *)drbg;
287 state->bytesLeft = 0;
288 state->custom = info->custom; //we only need to get the custom parameter from the info structure.
289
290 int rc = validate_inputs(state , entropyLength, 0, psLength);
291 if(rc!=CCDRBG_STATUS_OK){
292 //clear everything if cannot initialize. The idea is that if the caller doesn't check the output of init() and init() fails,
293 //the system crashes by NULL dereferencing after a call to generate, rather than generating bad random numbers.
294 done(drbg);
295 return rc;
296 }
297
298 const struct ccdigest_info *di = state->custom->di;
299 state->vsize = di->output_size;
300 state->keysize = di->output_size;
301 state->vptr=state->v;
302 state->nextvptr=state->v+state->vsize;
303
304 // 7. (V, Key, reseed_counter) = HMAC_DRBG_Instantiate_algorithm (entropy_input, personalization_string).
305 hmac_dbrg_instantiate_algorithm(drbg, entropyLength, entropy, nonceLength, nonce, psLength, ps);
306
307 #if DRBG_NISTHMAC_DEBUG
308 dumpState("Init: ", state);
309 #endif
310 return CCDRBG_STATUS_OK;
311
312 }
313
314 /*
315 10.1.2.4 Reseeding an HMAC_DRBG Instantiation
316 Notes for the reseed function specified in Section 9.2:
317 The reseeding of an HMAC_DRBG instantiation requires a call to the Reseed_function specified in Section 9.2.
318 Process step 6 of that function calls the reseed algorithm specified in this section. The values for min_length
319 are provided in Table 2 of Section 10.1.
320
321 The reseed algorithm:
322 Let HMAC_DRBG_Update be the function specified in Section 10.1.2.2. The following process or its equivalent
323 shall be used as the reseed algorithm for this DRBG mechanism (see step 6 of the reseed process in Section 9.2):
324
325 HMAC_DRBG_Reseed_algorithm (working_state, entropy_input, additional_input):
326 1. working_state: The current values for V, Key and reseed_counter (see Section 10.1.2.1).
327 2. entropy_input: The string of bits obtained from the source of entropy input.
328 3. additional_input: The additional input string received from the consuming application.
329 Note that the length of the additional_input string may be zero.
330
331 Output:
332 1. new_working_state: The new values for V, Key and reseed_counter. HMAC_DRBG Reseed Process:
333 1. seed_material = entropy_input || additional_input.
334 2. (Key, V) = HMAC_DRBG_Update (seed_material, Key, V). 3. reseed_counter = 1.
335 4. Return V, Key and reseed_counter as the new_working_state.
336 */
337
338 static int
339 reseed(struct ccdrbg_state *drbg,
340 size_t entropyLength, const void *entropy,
341 size_t additionalLength, const void *additional)
342 {
343
344 struct ccdrbg_nisthmac_state *state = (struct ccdrbg_nisthmac_state *)drbg;
345 int rc = validate_inputs(state, entropyLength, additionalLength, 0);
346 if(rc!=CCDRBG_STATUS_OK) return rc;
347
348 int rx = hmac_dbrg_update(drbg, entropyLength, entropy, additionalLength, additional, 0, NULL);
349 state->reseed_counter = 1;
350
351 #if DRBG_NISTHMAC_DEBUG
352 dumpState("Reseed: ", state);
353 #endif
354 return rx;
355 }
356
357 /*
358 HMAC_DRBG_Generate_algorithm:
359 Input: bitstring (V, Key), integer (reseed_counter, requested_number_of_bits).
360 Output: string status, bitstring (pseudorandom_bits, V, Key), integer reseed_counter.
361
362 Process:
363 1. If (reseed_counter ≥ 10,000), then Return (“Reseed required”, Null, V, Key, reseed_counter).
364 2. temp = Null.
365 3. While (len (temp) < requested_no_of_bits) do:
366 3.1 V = HMAC (Key, V).
367 3.2 temp = temp || V.
368 4. pseudorandom_bits = Leftmost (requested_no_of_bits) of temp.
369 5. (Key, V) = HMAC_DRBG_Update (Null, Key, V).
370 6. reseed_counter = reseed_counter + 1.
371 7. Return (“Success”, pseudorandom_bits, V, Key, reseed_counter).
372 */
373
374 static int validate_gen_params(uint64_t reseed_counter, size_t dataOutLength, size_t additionalLength)
375
376 {
377 int rc=CCDRBG_STATUS_PARAM_ERROR;
378
379 // Zero byte in one request is a valid use-case (21208820)
380 cc_require (dataOutLength <= CCDRBG_MAX_REQUEST_SIZE, end); //Requested too many bytes in one request
381 cc_require (additionalLength<=CCDRBG_MAX_ADDITIONALINPUT_SIZE, end); //Additional input too long
382
383 // 1. If (reseed_counter > 2^^48), then Return (“Reseed required”, Null, V, Key, reseed_counter).
384 rc = CCDRBG_STATUS_NEED_RESEED;
385 cc_require (reseed_counter <= CCDRBG_RESEED_INTERVAL, end); //Reseed required
386
387 rc=CCDRBG_STATUS_OK;
388
389 end:
390 return rc;
391 }
392
393 static int generate(struct ccdrbg_state *drbg, size_t dataOutLength, void *dataOut,
394 size_t additionalLength, const void *additional)
395 {
396 struct ccdrbg_nisthmac_state *state = (struct ccdrbg_nisthmac_state *)drbg;
397 const struct ccdrbg_nisthmac_custom *custom = state->custom;
398 const struct ccdigest_info *di = custom->di;
399
400 int rc = validate_gen_params(state->reseed_counter, dataOutLength, additional==NULL?0:additionalLength);
401 if(rc!=CCDRBG_STATUS_OK) return rc;
402
403 // 2. If additional_input ≠ Null, then (Key, V) = HMAC_DRBG_Update (additional_input, Key, V).
404 if (additional && additionalLength)
405 hmac_dbrg_update(drbg, additionalLength, additional, 0, NULL, 0, NULL);
406
407 // hmac_dbrg_generate_algorithm
408 char *outPtr = (char *) dataOut;
409 while (dataOutLength > 0) {
410 if (!state->bytesLeft) {
411 // 5. V=HMAC(K,V).
412 cchmac(di, state->keysize, state->key, state->vsize, state->nextvptr, state->vptr); // Won't be returned
413 // FIPS 140-2 4.9.2 Conditional Tests
414 // "Each subsequent generation of an n-bit block shall be compared with the previously generated block. The test shall fail if any two compared n-bit blocks are equal."
415 if (0==cc_cmp_safe(state->vsize, state->vptr, state->nextvptr)) {
416 //The world as we know it has come to an end
417 //the DRBG data structure is zeroized. subsequent calls to
418 //DRBG ends up in NULL dereferencing and/or unpredictable state.
419 //catastrophic error in SP 800-90A
420 done(drbg);
421 rc=CCDRBG_STATUS_ABORT;
422 cc_abort(NULL);
423 goto errOut;
424 }
425 CC_SWAP(state->nextvptr, state->vptr);
426 state->bytesLeft = state->vsize;
427 #if DRBG_NISTHMAC_DEBUG
428 cc_print("generate blk: ", state->vsize, state->vptr);
429 #endif
430 }
431 size_t outLength = dataOutLength > state->bytesLeft ? state->bytesLeft : dataOutLength;
432 CC_MEMCPY(outPtr, state->vptr, outLength);
433 state->bytesLeft -= outLength;
434 outPtr += outLength;
435 dataOutLength -= outLength;
436 }
437
438 // 6. (Key, V) = HMAC_DRBG_Update (additional_input, Key, V).
439 hmac_dbrg_update(drbg, additionalLength, additional, 0, NULL, 0, NULL);
440
441 // 7. reseed_counter = reseed_counter + 1.
442 state->reseed_counter++;
443
444 #if DRBG_NISTHMAC_DEBUG
445 dumpState("generate end: ", state);
446 cc_print("generate end nxt: ", state->vsize, state->nextvptr);
447 #endif
448 rc=CCDRBG_STATUS_OK;
449 errOut:
450 return rc;
451 }
452
453 static void done(struct ccdrbg_state *drbg)
454 {
455 struct ccdrbg_nisthmac_state *state=(struct ccdrbg_nisthmac_state *)drbg;
456 cc_clear(sizeof(struct ccdrbg_nisthmac_state), state); //clear v, key as well as internal variables
457 }
458
459 struct ccdrbg_info ccdrbg_nisthmac_info = {
460 .size = sizeof(struct ccdrbg_nisthmac_state) + sizeof(struct ccdrbg_nisthmac_custom),
461 .init = init,
462 .reseed = reseed,
463 .generate = generate,
464 .done = done,
465 .custom = NULL
466 };
467
468 /* This initializes an info object with the right options */
469 void ccdrbg_factory_nisthmac(struct ccdrbg_info *info, const struct ccdrbg_nisthmac_custom *custom)
470 {
471 info->size = sizeof(struct ccdrbg_nisthmac_state) + sizeof(struct ccdrbg_nisthmac_custom);
472 info->init = init;
473 info->generate = generate;
474 info->reseed = reseed;
475 info->done = done;
476 info->custom = custom;
477 };
478