]> git.saurik.com Git - apple/xnu.git/blame - osfmk/corecrypto/ccdbrg/src/ccdrbg_nisthmac.c
xnu-3247.1.106.tar.gz
[apple/xnu.git] / osfmk / corecrypto / ccdbrg / src / ccdrbg_nisthmac.c
CommitLineData
fe8ab488
A
1/*
2 * ccdrbg_nisthmac.c
3 * corecrypto
4 *
3e170ce0
A
5 * Created on 05/09/2014
6 *
7 * Copyright (c) 2014,2015 Apple Inc. All rights reserved.
fe8ab488
A
8 *
9 */
10
11#include <corecrypto/ccdrbg.h>
12#include <corecrypto/cchmac.h>
13#include <corecrypto/ccsha2.h>
3e170ce0 14#include <corecrypto/cc_priv.h>
fe8ab488 15#include <corecrypto/cc_debug.h>
3e170ce0 16#include <corecrypto/cc_macros.h>
fe8ab488
A
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/*
3e170ce0
A
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 */
fe8ab488
A
38
39/*
3e170ce0 40 The Get_entropy_input function is specified in pseudocode in [SP 800-90C] for various RBG constructions;
fe8ab488
A
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
3e170ce0
A
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
fe8ab488
A
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
fe8ab488
A
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)
3e170ce0
A
82
83#define MIN_REQ_ENTROPY(di) ((di)->output_size/2)
fe8ab488
A
84
85struct ccdrbg_nisthmac_state {
3e170ce0
A
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
fe8ab488
A
89 size_t vsize;
90 size_t keysize;
91 uint8_t v[NH_MAX_OUTPUT_BLOCK_SIZE];
92 uint8_t key[NH_MAX_KEY_SIZE];
93};
94
95#ifdef DEBUGFOO
96static void dumpState(const char *label, struct ccdrbg_nisthmac_state *state) {
97 cc_print(label, state->vsize, state->v);
98 cc_print(label, state->keysize, state->key);
99}
100#endif
101
102/*
103 NIST SP 800-90A, Rev. 1 HMAC_DRBG April 2014, p 46
3e170ce0 104
fe8ab488
A
105 HMAC_DRBG_Update (provided_data, K, V):
106 1. provided_data: The data to be used.
107 2. K: The current value of Key.
108 3. V: The current value of V.
109 Output:
110 1. K: The new value for Key.
111 2. V: The new value for V.
3e170ce0 112
fe8ab488 113 HMAC_DRBG Update Process:
3e170ce0 114
fe8ab488
A
115 1. K = HMAC (K, V || 0x00 || provided_data).
116 2. V=HMAC(K,V).
117 3. If (provided_data = Null), then return K and V.
118 4. K = HMAC (K, V || 0x01 || provided_data).
119 5. V=HMAC(K,V).
120 6. Return K and V.
121 */
122
123// was: unsigned long providedDataLength, const void *providedData
124
125/*
126 To handle the case where we have three strings that are concatenated,
127 we pass in three (ptr, len) pairs
128 */
129
130static int hmac_dbrg_update(struct ccdrbg_state *drbg,
131 unsigned long daLen, const void *da,
132 unsigned long dbLen, const void *db,
133 unsigned long dcLen, const void *dc
134 )
135{
136 struct ccdrbg_nisthmac_state *state = (struct ccdrbg_nisthmac_state *)drbg;
3e170ce0
A
137 const struct ccdigest_info *di = state->custom->di;
138
fe8ab488
A
139 const unsigned char cZero = 0x00;
140 const unsigned char cOne = 0x01;
141 cchmac_ctx_decl(di->state_size, di->block_size, ctx);
3e170ce0 142
fe8ab488 143 cchmac_init(di, ctx, state->keysize, state->key);
3e170ce0 144
fe8ab488
A
145 // 1. K = HMAC (K, V || 0x00 || provided_data).
146 cchmac_update(di, ctx, state->vsize, state->v);
147 cchmac_update(di, ctx, 1, &cZero);
148 if (da && daLen) cchmac_update(di, ctx, daLen, da);
149 if (db && dbLen) cchmac_update(di, ctx, dbLen, db);
150 if (dc && dcLen) cchmac_update(di, ctx, dcLen, dc);
151 cchmac_final(di, ctx, state->key);
3e170ce0 152
fe8ab488
A
153 // 2. V=HMAC(K,V).
154 cchmac(di, state->keysize, state->key, state->vsize, state->v, state->v);
3e170ce0 155
fe8ab488
A
156 // 3. If (provided_data = Null), then return K and V.
157 // One parameter must be non-empty, or return
158 if (!((da && daLen) || (db && dbLen) || (dc && dcLen)))
3e170ce0
A
159 return CCDRBG_STATUS_OK;
160
fe8ab488
A
161 // 4. K = HMAC (K, V || 0x01 || provided_data).
162 cchmac_init(di, ctx, state->keysize, state->key);
163 cchmac_update(di, ctx, state->vsize, state->v);
164 cchmac_update(di, ctx, 1, &cOne);
165 if (da && daLen) cchmac_update(di, ctx, daLen, da);
166 if (db && dbLen) cchmac_update(di, ctx, dbLen, db);
167 if (dc && dcLen) cchmac_update(di, ctx, dcLen, dc);
168 cchmac_final(di, ctx, state->key);
3e170ce0 169
fe8ab488
A
170 // 5. V=HMAC(K,V).
171 cchmac(di, state->keysize, state->key, state->vsize, state->v, state->v);
3e170ce0
A
172
173 return CCDRBG_STATUS_OK;
174}
fe8ab488 175
3e170ce0
A
176//make sure state is initialized, before calling this function
177static int validate_inputs(struct ccdrbg_nisthmac_state *state,
178 unsigned long entropyLength,
179 unsigned long additionalInputLength,
180 unsigned long psLength)
181{
182 int rc;
183 const struct ccdrbg_nisthmac_custom *custom=state->custom;
184 const struct ccdigest_info *di = custom->di;
185
186 rc =CCDRBG_STATUS_ERROR;
187 //buffer size checks
188 cc_require (di->output_size<=sizeof(state->v), end); //digest size too long
189 cc_require (di->output_size<=sizeof(state->key), end); //digest size too long
190
191 //NIST SP800 compliance checks
192 //the following maximum checks are redundant if long is 32 bits.
193
194 rc=CCDRBG_STATUS_PARAM_ERROR;
195 cc_require (psLength <= CCDRBG_MAX_PSINPUT_SIZE, end); //personalization string too long
196 cc_require (entropyLength <= CCDRBG_MAX_ENTROPY_SIZE, end); //supplied too much entropy
197 cc_require (additionalInputLength <= CCDRBG_MAX_ADDITIONALINPUT_SIZE, end); //additional input too long
198 cc_require (entropyLength >= MIN_REQ_ENTROPY(di), end); //supplied too litle entropy
199
200 cc_require(di->output_size<=NH_MAX_OUTPUT_BLOCK_SIZE, end); //the requested security strength is not supported
201
202 rc=CCDRBG_STATUS_OK;
203end:
204 return rc;
fe8ab488
A
205}
206
207/*
3e170ce0
A
208 NIST SP 800-90A, Rev. 1 April 2014 B.2.2, p 84
209
210 HMAC_DRBG_Instantiate_algorithm (...):
211 Input: bitstring (entropy_input, personalization_string).
212 Output: bitstring (V, Key), integer reseed_counter.
213
214 Process:
215 1. seed_material = entropy_input || personalization_string.
216 2. Set Key to outlen bits of zeros.
217 3. Set V to outlen/8 bytes of 0x01.
218 4. (Key, V) = HMAC_DRBG_Update (seed_material, Key, V).
219 5. reseed_counter = 1.
220 6. Return (V, Key, reseed_counter).
221 */
fe8ab488
A
222
223// This version does not do memory allocation
3e170ce0 224//SP800-90 A: Required minimum entropy for instantiate and reseed=security_strength
fe8ab488
A
225
226static int hmac_dbrg_instantiate_algorithm(struct ccdrbg_state *drbg,
227 unsigned long entropyLength, const void *entropy,
228 unsigned long nonceLength, const void *nonce,
229 unsigned long psLength, const void *ps)
230{
231 // TODO: The NIST code passes nonce (i.e. HMAC key) to generate, but cc interface isn't set up that way
3e170ce0
A
232 struct ccdrbg_nisthmac_state *state = (struct ccdrbg_nisthmac_state *)drbg;
233
fe8ab488 234 // 1. seed_material = entropy_input || nonce || personalization_string.
3e170ce0 235
fe8ab488
A
236 // 2. Set Key to outlen bits of zeros.
237 cc_zero(state->keysize, state->key);
3e170ce0 238
fe8ab488
A
239 // 3. Set V to outlen/8 bytes of 0x01.
240 CC_MEMSET(state->v, 0x01, state->vsize);
3e170ce0 241
fe8ab488
A
242 // 4. (Key, V) = HMAC_DRBG_Update (seed_material, Key, V).
243 hmac_dbrg_update(drbg, entropyLength, entropy, nonceLength, nonce, psLength, ps);
3e170ce0 244
fe8ab488
A
245 // 5. reseed_counter = 1.
246 state->reseed_counter = 1;
247
3e170ce0 248 return CCDRBG_STATUS_OK;
fe8ab488
A
249}
250
251// In NIST terminology, the nonce is the HMAC key and ps is the personalization string
3e170ce0
A
252// We assume that the caller has passed in
253// min_entropy = NH_REQUIRED_MIN_ENTROPY(security_strength)
254// bytes of entropy
255
256static void done(struct ccdrbg_state *drbg);
fe8ab488
A
257
258static int init(const struct ccdrbg_info *info, struct ccdrbg_state *drbg,
259 unsigned long entropyLength, const void* entropy,
260 unsigned long nonceLength, const void* nonce,
261 unsigned long psLength, const void* ps)
262{
263 struct ccdrbg_nisthmac_state *state=(struct ccdrbg_nisthmac_state *)drbg;
fe8ab488 264 state->bytesLeft = 0;
3e170ce0
A
265 state->custom = info->custom; //we only need to get the custom parameter from the info structure.
266
267 int rc = validate_inputs(state , entropyLength, 0, psLength);
268 if(rc!=CCDRBG_STATUS_OK){
269 //clear everything if cannot initialize. The idea is that if the caller doesn't check the output of init() and init() fails,
270 //the system crashes by NULL dereferencing after a call to generate, rather than generating bad random numbers.
271 done(drbg);
272 return rc;
273 }
fe8ab488 274
3e170ce0
A
275 const struct ccdigest_info *di = state->custom->di;
276 state->vsize = di->output_size;
277 state->keysize = di->output_size;
278
fe8ab488 279 // 7. (V, Key, reseed_counter) = HMAC_DRBG_Instantiate_algorithm (entropy_input, personalization_string).
fe8ab488
A
280 hmac_dbrg_instantiate_algorithm(drbg, entropyLength, entropy, nonceLength, nonce, psLength, ps);
281
282#ifdef DEBUGFOO
283 dumpState("Init: ", state);
284#endif
3e170ce0
A
285 return CCDRBG_STATUS_OK;
286
fe8ab488
A
287}
288
289/*
3e170ce0
A
290 10.1.2.4 Reseeding an HMAC_DRBG Instantiation
291 Notes for the reseed function specified in Section 9.2:
292 The reseeding of an HMAC_DRBG instantiation requires a call to the Reseed_function specified in Section 9.2.
293 Process step 6 of that function calls the reseed algorithm specified in this section. The values for min_length
294 are provided in Table 2 of Section 10.1.
295
296 The reseed algorithm:
297 Let HMAC_DRBG_Update be the function specified in Section 10.1.2.2. The following process or its equivalent
298 shall be used as the reseed algorithm for this DRBG mechanism (see step 6 of the reseed process in Section 9.2):
299
300 HMAC_DRBG_Reseed_algorithm (working_state, entropy_input, additional_input):
301 1. working_state: The current values for V, Key and reseed_counter (see Section 10.1.2.1).
302 2. entropy_input: The string of bits obtained from the source of entropy input.
303 3. additional_input: The additional input string received from the consuming application.
304 Note that the length of the additional_input string may be zero.
305
306 Output:
307 1. new_working_state: The new values for V, Key and reseed_counter. HMAC_DRBG Reseed Process:
308 1. seed_material = entropy_input || additional_input.
309 2. (Key, V) = HMAC_DRBG_Update (seed_material, Key, V). 3. reseed_counter = 1.
310 4. Return V, Key and reseed_counter as the new_working_state.
311 */
fe8ab488 312
3e170ce0
A
313static int
314reseed(struct ccdrbg_state *drbg,
315 unsigned long entropyLength, const void *entropy,
316 unsigned long additionalLength, const void *additional)
317{
318
319 struct ccdrbg_nisthmac_state *state = (struct ccdrbg_nisthmac_state *)drbg;
320 int rc = validate_inputs(state, entropyLength, additionalLength, 0);
321 if(rc!=CCDRBG_STATUS_OK) return rc;
322
323 int rx = hmac_dbrg_update(drbg, entropyLength, entropy, additionalLength, additional, 0, NULL);
fe8ab488 324 state->reseed_counter = 1;
3e170ce0 325
fe8ab488
A
326#ifdef DEBUGFOO
327 dumpState("Reseed: ", state);
328#endif
329 return rx;
330}
331
332/*
3e170ce0
A
333 HMAC_DRBG_Generate_algorithm:
334 Input: bitstring (V, Key), integer (reseed_counter, requested_number_of_bits).
335 Output: string status, bitstring (pseudorandom_bits, V, Key), integer reseed_counter.
336
337 Process:
338 1. If (reseed_counter ≥ 10,000), then Return (“Reseed required”, Null, V, Key, reseed_counter).
339 2. temp = Null.
340 3. While (len (temp) < requested_no_of_bits) do:
341 3.1 V = HMAC (Key, V).
342 3.2 temp = temp || V.
343 4. pseudorandom_bits = Leftmost (requested_no_of_bits) of temp.
344 5. (Key, V) = HMAC_DRBG_Update (Null, Key, V).
345 6. reseed_counter = reseed_counter + 1.
346 7. Return (“Success”, pseudorandom_bits, V, Key, reseed_counter).
347 */
fe8ab488 348
3e170ce0 349static int validate_gen_params(uint64_t reseed_counter, unsigned long dataOutLength, unsigned long additionalLength)
fe8ab488 350
3e170ce0
A
351{
352 int rc=CCDRBG_STATUS_PARAM_ERROR;
353
354 cc_require (dataOutLength >= 1, end); //Requested zero byte in one request
355 cc_require (dataOutLength <= CCDRBG_MAX_REQUEST_SIZE, end); //Requested too many bytes in one request
356 cc_require (additionalLength<=CCDRBG_MAX_ADDITIONALINPUT_SIZE, end); //Additional input too long
357
fe8ab488 358 // 1. If (reseed_counter > 2^^48), then Return (“Reseed required”, Null, V, Key, reseed_counter).
3e170ce0
A
359 rc = CCDRBG_STATUS_NEED_RESEED;
360 cc_require (reseed_counter <= CCDRBG_RESEED_INTERVAL, end); //Reseed required
361
362 rc=CCDRBG_STATUS_OK;
363
364end:
365 return rc;
366}
fe8ab488 367
3e170ce0
A
368static int generate(struct ccdrbg_state *drbg, unsigned long dataOutLength, void *dataOut,
369 unsigned long additionalLength, const void *additional)
370{
371 struct ccdrbg_nisthmac_state *state = (struct ccdrbg_nisthmac_state *)drbg;
372 const struct ccdrbg_nisthmac_custom *custom = state->custom;
373 const struct ccdigest_info *di = custom->di;
374
375 int rc = validate_gen_params(state->reseed_counter, dataOutLength, additional==NULL?0:additionalLength);
376 if(rc!=CCDRBG_STATUS_OK) return rc;
377
fe8ab488 378 // 2. If additional_input ≠ Null, then (Key, V) = HMAC_DRBG_Update (additional_input, Key, V).
3e170ce0
A
379 if (additional && additionalLength)
380 hmac_dbrg_update(drbg, additionalLength, additional, 0, NULL, 0, NULL);
381
fe8ab488 382 // hmac_dbrg_generate_algorithm
3e170ce0
A
383 char *outPtr = (char *) dataOut;
384 while (dataOutLength > 0) {
fe8ab488
A
385 if (!state->bytesLeft) {
386 // 5. V=HMAC(K,V).
387 cchmac(di, state->keysize, state->key, state->vsize, state->v, state->v);
388 state->bytesLeft = di->output_size;//di->output_size; state->vsize
389 }
3e170ce0
A
390 size_t outLength = dataOutLength > state->bytesLeft ? state->bytesLeft : dataOutLength;
391 CC_MEMCPY(outPtr, state->v, outLength);
fe8ab488
A
392 state->bytesLeft -= outLength;
393 outPtr += outLength;
3e170ce0 394 dataOutLength -= outLength;
fe8ab488 395 }
3e170ce0 396
fe8ab488 397 // 6. (Key, V) = HMAC_DRBG_Update (additional_input, Key, V).
3e170ce0
A
398 hmac_dbrg_update(drbg, additionalLength, additional, 0, NULL, 0, NULL);
399
fe8ab488
A
400 // 7. reseed_counter = reseed_counter + 1.
401 state->reseed_counter++;
3e170ce0 402
fe8ab488
A
403#ifdef DEBUGFOO
404 dumpState("generate: ", state);
405#endif
406
3e170ce0 407 return CCDRBG_STATUS_OK;
fe8ab488
A
408}
409
410static void done(struct ccdrbg_state *drbg)
411{
412 struct ccdrbg_nisthmac_state *state=(struct ccdrbg_nisthmac_state *)drbg;
3e170ce0 413 cc_clear(sizeof(struct ccdrbg_nisthmac_state), state); //clear v, key as well as internal variables
fe8ab488
A
414}
415
416struct ccdrbg_info ccdrbg_nisthmac_info = {
417 .size = sizeof(struct ccdrbg_nisthmac_state) + sizeof(struct ccdrbg_nisthmac_custom),
418 .init = init,
419 .reseed = reseed,
420 .generate = generate,
421 .done = done,
422 .custom = NULL
423};
424
425/* This initializes an info object with the right options */
426void ccdrbg_factory_nisthmac(struct ccdrbg_info *info, const struct ccdrbg_nisthmac_custom *custom)
427{
428 info->size = sizeof(struct ccdrbg_nisthmac_state) + sizeof(struct ccdrbg_nisthmac_custom);
429 info->init = init;
430 info->generate = generate;
431 info->reseed = reseed;
432 info->done = done;
433 info->custom = custom;
434};
435