5 * Created by John Hurley on 04/30/14.
6 * Copyright 2014 Apple, Inc. All rights reserved.
10 #include <corecrypto/ccdrbg.h>
11 #include <corecrypto/cchmac.h>
12 #include <corecrypto/ccsha2.h>
14 #include <corecrypto/cc_debug.h>
19 #include <pexpert/pexpert.h>
20 static int hmac_dbrg_error(int val
, __unused
const char *msg
) {
24 static int hmac_dbrg_error(int val
, const char *msg
) {
27 snprintf(buffer
, sizeof(buffer
)-1, "Error: %s", msg
);
28 cc_print(buffer
, 0, NULL
);
35 // http://csrc.nist.gov/groups/STM/cavp/#05
36 // http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip
40 This HMAC DBRG is described in:
42 SP 800-90 A Rev. 1 (2nd Draft)
43 DRAFT Recommendation for Random Number Generation Using Deterministic Random Bit Generators
46 SP 800-90A (revision 1), Recommendation for Random Number Generation Using Deterministic Random Bit Generators
47 http://csrc.nist.gov/publications/drafts/800-90/sp800_90a_r1_draft.pdf
50 - 10.1.2 HMAC_DRBG (p 45)
51 - B.2 HMAC_DRBGExample (p 83)
53 We only support one security strength, 256 bits
54 In addition, we limit the personalization string to 20 bytes
55 Note that the example in B.2 is very limited, refer to §10.1.2 for more
61 The Get_entropy_input function is specified in pseudocode in [SP 800-90C] for various RBG constructions;
62 however, in general, the function has the following meaning:
63 Get_entropy_input: A function that is used to obtain entropy input. The function call is:
64 (status, entropy_input) = Get_entropy_input (min_entropy, min_ length, max_ length, prediction_resistance_request),
65 which requests a string of bits (entropy_input) with at least min_entropy bits of entropy. The length for the string
66 shall be equal to or greater than min_length bits, and less than or equal to max_length bits. The
67 prediction_resistance_request parameter indicates whether or not prediction resistance is to be provided during the request
68 (i.e., whether fresh entropy is required). A status code is also returned from the function.
72 Check the validity of the input parameters.
73 1. If (requested_instantiation_security_strength > 256), then Return (“Invalid
74 requested_instantiation_security_strength”, −1).
75 2. If (len (personalization_string) > 160), then Return (“Personalization_string
77 Comment: Set the security_strength to one of the valid security strengths.
78 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.
79 Comment: Get the entropy_input and the nonce.
80 4. min_entropy = 1.5 × security_strength.
81 5. (status, entropy_input) = Get_entropy_input (min_entropy, 1000).
82 6. If (status ≠ “Success”), then Return (status, −1).
86 1. highest_supported_security_strength = 256.
87 2. Output block (outlen) = 256 bits.
88 3. Required minimum entropy for the entropy input at instantiation = 3/2 security_strength (this includes the entropy required for the nonce).
89 4. Seed length (seedlen) = 440 bits.
90 5. Maximum number of bits per request (max_number_of_bits_per_request) = 7500
92 6. Reseed_interval (reseed_ interval) = 10,000 requests.
93 7. Maximum length of the personalization string (max_personalization_string_length) = 160 bits.
94 8. Maximum length of the entropy input (max _length) = 1000 bits.
98 // Defines below based on 10.1, Table 2: Definitions for Hash-Based DRBG Mechanisms (p 39)
101 #define NH_MAX_SECURITY_STRENGTH 256 // in bits
102 #define NH_MAX_OUTPUT_BLOCK_SIZE (CCSHA512_OUTPUT_SIZE) // 512 bits, i.e. 64 bytes (CCSHA512_OUTPUT_SIZE)
103 #define NH_MAX_KEY_SIZE (CCSHA512_OUTPUT_SIZE) // 512 bits, i.e. 64 bytes (CCSHA512_OUTPUT_SIZE)
104 #define NH_REQUIRED_MIN_ENTROPY(s) (3*(s)/2)
105 #define NH_MAX_BYTES_PER_REQUEST (0xffff) // in bytes, 2^^16
106 #define NH_RESEED_INTERVAL ((unsigned long)0xffffffffffff) // 2^^48 requests between reseeds
107 #define NH_MAX_PERSONALIZE_LEN (1024) // 1024 bytes
108 #define NH_MIN_ENTROPY_LEN (NH_MAX_SECURITY_STRENGTH/8)
109 #define NH_MAX_ENTROPY_LEN (0xffffffff) // in bytes, 2^^32
111 struct ccdrbg_nisthmac_state
{
112 const struct ccdrbg_info
*info
;
114 size_t reseed_counter
;
117 uint8_t v
[NH_MAX_OUTPUT_BLOCK_SIZE
];
118 uint8_t key
[NH_MAX_KEY_SIZE
];
122 static void dumpState(const char *label
, struct ccdrbg_nisthmac_state
*state
) {
123 cc_print(label
, state
->vsize
, state
->v
);
124 cc_print(label
, state
->keysize
, state
->key
);
129 NIST SP 800-90A, Rev. 1 HMAC_DRBG April 2014, p 46
131 HMAC_DRBG_Update (provided_data, K, V):
132 1. provided_data: The data to be used.
133 2. K: The current value of Key.
134 3. V: The current value of V.
136 1. K: The new value for Key.
137 2. V: The new value for V.
139 HMAC_DRBG Update Process:
141 1. K = HMAC (K, V || 0x00 || provided_data).
143 3. If (provided_data = Null), then return K and V.
144 4. K = HMAC (K, V || 0x01 || provided_data).
149 // was: unsigned long providedDataLength, const void *providedData
152 To handle the case where we have three strings that are concatenated,
153 we pass in three (ptr, len) pairs
156 static int hmac_dbrg_update(struct ccdrbg_state
*drbg
,
157 unsigned long daLen
, const void *da
,
158 unsigned long dbLen
, const void *db
,
159 unsigned long dcLen
, const void *dc
162 struct ccdrbg_nisthmac_state
*state
= (struct ccdrbg_nisthmac_state
*)drbg
;
163 const struct ccdrbg_nisthmac_custom
*custom
= state
->info
->custom
;
164 const struct ccdigest_info
*di
= custom
->di
;
166 const unsigned char cZero
= 0x00;
167 const unsigned char cOne
= 0x01;
168 cchmac_ctx_decl(di
->state_size
, di
->block_size
, ctx
);
170 cchmac_init(di
, ctx
, state
->keysize
, state
->key
);
171 // 1. K = HMAC (K, V || 0x00 || provided_data).
172 cchmac_update(di
, ctx
, state
->vsize
, state
->v
);
173 cchmac_update(di
, ctx
, 1, &cZero
);
174 if (da
&& daLen
) cchmac_update(di
, ctx
, daLen
, da
);
175 if (db
&& dbLen
) cchmac_update(di
, ctx
, dbLen
, db
);
176 if (dc
&& dcLen
) cchmac_update(di
, ctx
, dcLen
, dc
);
177 cchmac_final(di
, ctx
, state
->key
);
180 cchmac(di
, state
->keysize
, state
->key
, state
->vsize
, state
->v
, state
->v
);
182 // 3. If (provided_data = Null), then return K and V.
183 // One parameter must be non-empty, or return
184 if (!((da
&& daLen
) || (db
&& dbLen
) || (dc
&& dcLen
)))
187 // 4. K = HMAC (K, V || 0x01 || provided_data).
188 cchmac_init(di
, ctx
, state
->keysize
, state
->key
);
189 cchmac_update(di
, ctx
, state
->vsize
, state
->v
);
190 cchmac_update(di
, ctx
, 1, &cOne
);
191 if (da
&& daLen
) cchmac_update(di
, ctx
, daLen
, da
);
192 if (db
&& dbLen
) cchmac_update(di
, ctx
, dbLen
, db
);
193 if (dc
&& dcLen
) cchmac_update(di
, ctx
, dcLen
, dc
);
194 cchmac_final(di
, ctx
, state
->key
);
197 cchmac(di
, state
->keysize
, state
->key
, state
->vsize
, state
->v
, state
->v
);
203 NIST SP 800-90A, Rev. 1 April 2014 B.2.2, p 84
205 HMAC_DRBG_Instantiate_algorithm (...):
206 Input: bitstring (entropy_input, personalization_string).
207 Output: bitstring (V, Key), integer reseed_counter.
210 1. seed_material = entropy_input || personalization_string.
211 2. Set Key to outlen bits of zeros.
212 3. Set V to outlen/8 bytes of 0x01.
213 4. (Key, V) = HMAC_DRBG_Update (seed_material, Key, V).
214 5. reseed_counter = 1.
215 6. Return (V, Key, reseed_counter).
218 // This version does not do memory allocation
220 static int hmac_dbrg_instantiate_algorithm(struct ccdrbg_state
*drbg
,
221 unsigned long entropyLength
, const void *entropy
,
222 unsigned long nonceLength
, const void *nonce
,
223 unsigned long psLength
, const void *ps
)
225 // TODO: The NIST code passes nonce (i.e. HMAC key) to generate, but cc interface isn't set up that way
227 struct ccdrbg_nisthmac_state
*state
=(struct ccdrbg_nisthmac_state
*)drbg
;
229 // 1. seed_material = entropy_input || nonce || personalization_string.
231 // 2. Set Key to outlen bits of zeros.
232 cc_zero(state
->keysize
, state
->key
);
234 // 3. Set V to outlen/8 bytes of 0x01.
235 CC_MEMSET(state
->v
, 0x01, state
->vsize
);
237 // 4. (Key, V) = HMAC_DRBG_Update (seed_material, Key, V).
238 hmac_dbrg_update(drbg
, entropyLength
, entropy
, nonceLength
, nonce
, psLength
, ps
);
240 // 5. reseed_counter = 1.
241 state
->reseed_counter
= 1;
246 // In NIST terminology, the nonce is the HMAC key and ps is the personalization string
248 static int init(const struct ccdrbg_info
*info
, struct ccdrbg_state
*drbg
,
249 unsigned long entropyLength
, const void* entropy
,
250 unsigned long nonceLength
, const void* nonce
,
251 unsigned long psLength
, const void* ps
)
253 struct ccdrbg_nisthmac_state
*state
=(struct ccdrbg_nisthmac_state
*)drbg
;
254 const struct ccdrbg_nisthmac_custom
*custom
= NULL
;
255 const struct ccdigest_info
*di
= NULL
;
256 size_t security_strength
;
259 state
->bytesLeft
= 0;
261 custom
= state
->info
->custom
;
263 state
->vsize
= di
->output_size
; // TODO: state_size? or output_size
264 state
->keysize
= di
->output_size
; // TODO: state size?
266 security_strength
= NH_MAX_SECURITY_STRENGTH
;
268 if (psLength
> NH_MAX_PERSONALIZE_LEN
) // "Personalization_string too long"
269 return hmac_dbrg_error(-1, "Personalization_string too long");
271 if (entropyLength
> NH_MAX_ENTROPY_LEN
) // Supplied too much entropy
272 return hmac_dbrg_error(-1, "Supplied too much entropy");
274 // 4. min_entropy = 1.5 × security_strength.
275 min_entropy
= NH_REQUIRED_MIN_ENTROPY(security_strength
);
277 // 7. (V, Key, reseed_counter) = HMAC_DRBG_Instantiate_algorithm (entropy_input, personalization_string).
279 hmac_dbrg_instantiate_algorithm(drbg
, entropyLength
, entropy
, nonceLength
, nonce
, psLength
, ps
);
282 dumpState("Init: ", state
);
288 10.1.2.4 Reseeding an HMAC_DRBG Instantiation
289 Notes for the reseed function specified in Section 9.2:
290 The reseeding of an HMAC_DRBG instantiation requires a call to the Reseed_function specified in Section 9.2.
291 Process step 6 of that function calls the reseed algorithm specified in this section. The values for min_length
292 are provided in Table 2 of Section 10.1.
294 The reseed algorithm:
295 Let HMAC_DRBG_Update be the function specified in Section 10.1.2.2. The following process or its equivalent
296 shall be used as the reseed algorithm for this DRBG mechanism (see step 6 of the reseed process in Section 9.2):
298 HMAC_DRBG_Reseed_algorithm (working_state, entropy_input, additional_input):
299 1. working_state: The current values for V, Key and reseed_counter (see Section 10.1.2.1).
300 2. entropy_input: The string of bits obtained from the source of entropy input.
301 3. additional_input: The additional input string received from the consuming application.
302 Note that the length of the additional_input string may be zero.
305 1. new_working_state: The new values for V, Key and reseed_counter. HMAC_DRBG Reseed Process:
306 1. seed_material = entropy_input || additional_input.
307 2. (Key, V) = HMAC_DRBG_Update (seed_material, Key, V). 3. reseed_counter = 1.
308 4. Return V, Key and reseed_counter as the new_working_state.
311 static int reseed(struct ccdrbg_state
*drbg
,
312 unsigned long entropyLength
, const void *entropy
,
313 unsigned long inputlen
, const void *input
)
315 struct ccdrbg_nisthmac_state
*state
=(struct ccdrbg_nisthmac_state
*)drbg
;
317 int rx
= hmac_dbrg_update(drbg
, entropyLength
, entropy
, inputlen
, input
, 0, NULL
);
318 state
->reseed_counter
= 1;
321 dumpState("Reseed: ", state
);
327 HMAC_DRBG_Generate_algorithm:
328 Input: bitstring (V, Key), integer (reseed_counter, requested_number_of_bits).
329 Output: string status, bitstring (pseudorandom_bits, V, Key), integer reseed_counter.
332 1. If (reseed_counter ≥ 10,000), then Return (“Reseed required”, Null, V, Key, reseed_counter).
334 3. While (len (temp) < requested_no_of_bits) do:
335 3.1 V = HMAC (Key, V).
336 3.2 temp = temp || V.
337 4. pseudorandom_bits = Leftmost (requested_no_of_bits) of temp.
338 5. (Key, V) = HMAC_DRBG_Update (Null, Key, V).
339 6. reseed_counter = reseed_counter + 1.
340 7. Return (“Success”, pseudorandom_bits, V, Key, reseed_counter).
343 static int generate(struct ccdrbg_state
*drbg
, unsigned long numBytes
, void *outBytes
,
344 unsigned long inputLen
, const void *input
)
346 struct ccdrbg_nisthmac_state
*state
= (struct ccdrbg_nisthmac_state
*)drbg
;
347 const struct ccdrbg_nisthmac_custom
*custom
= state
->info
->custom
;
348 const struct ccdigest_info
*di
= custom
->di
;
350 if (numBytes
> NH_MAX_BYTES_PER_REQUEST
)
351 return hmac_dbrg_error(CCDRBG_STATUS_PARAM_ERROR
,
352 "Requested too many bytes in one request");
354 // 1. If (reseed_counter > 2^^48), then Return (“Reseed required”, Null, V, Key, reseed_counter).
355 if (state
->reseed_counter
> NH_RESEED_INTERVAL
)
356 return hmac_dbrg_error(CCDRBG_STATUS_NEED_RESEED
, "Reseed required");
358 // 2. If additional_input ≠ Null, then (Key, V) = HMAC_DRBG_Update (additional_input, Key, V).
359 if (input
&& inputLen
)
360 hmac_dbrg_update(drbg
, inputLen
, input
, 0, NULL
, 0, NULL
);
362 // hmac_dbrg_generate_algorithm
363 char *outPtr
= (char *) outBytes
;
364 while (numBytes
> 0) {
365 if (!state
->bytesLeft
) {
367 cchmac(di
, state
->keysize
, state
->key
, state
->vsize
, state
->v
, state
->v
);
368 state
->bytesLeft
= di
->output_size
;//di->output_size; state->vsize
370 size_t outLength
= numBytes
> state
->bytesLeft
? state
->bytesLeft
: numBytes
;
371 memcpy(outPtr
, state
->v
, outLength
);
372 state
->bytesLeft
-= outLength
;
374 numBytes
-= outLength
;
377 // 6. (Key, V) = HMAC_DRBG_Update (additional_input, Key, V).
378 hmac_dbrg_update(drbg
, inputLen
, input
, 0, NULL
, 0, NULL
);
380 // 7. reseed_counter = reseed_counter + 1.
381 state
->reseed_counter
++;
384 dumpState("generate: ", state
);
390 static void done(struct ccdrbg_state
*drbg
)
392 struct ccdrbg_nisthmac_state
*state
=(struct ccdrbg_nisthmac_state
*)drbg
;
393 cc_zero(sizeof(state
->v
), state
->v
);
394 cc_zero(sizeof(state
->key
), state
->key
);
397 struct ccdrbg_info ccdrbg_nisthmac_info
= {
398 .size
= sizeof(struct ccdrbg_nisthmac_state
) + sizeof(struct ccdrbg_nisthmac_custom
),
401 .generate
= generate
,
406 /* This initializes an info object with the right options */
407 void ccdrbg_factory_nisthmac(struct ccdrbg_info
*info
, const struct ccdrbg_nisthmac_custom
*custom
)
409 info
->size
= sizeof(struct ccdrbg_nisthmac_state
) + sizeof(struct ccdrbg_nisthmac_custom
);
411 info
->generate
= generate
;
412 info
->reseed
= reseed
;
414 info
->custom
= custom
;