]> git.saurik.com Git - apple/xnu.git/blob - osfmk/corecrypto/ccdbrg/src/ccdrbg_nisthmac.c
f797d03785e21f9cf824ad0bb36f4f4314db5993
[apple/xnu.git] / osfmk / corecrypto / ccdbrg / src / ccdrbg_nisthmac.c
1 /*
2 * ccdrbg_nisthmac.c
3 * corecrypto
4 *
5 * Created by John Hurley on 04/30/14.
6 * Copyright 2014 Apple, Inc. All rights reserved.
7 *
8 */
9
10 #include <corecrypto/ccdrbg.h>
11 #include <corecrypto/cchmac.h>
12 #include <corecrypto/ccsha2.h>
13 #if !CC_KERNEL
14 #include <corecrypto/cc_debug.h>
15 #endif
16
17
18 #if CC_KERNEL
19 #include <pexpert/pexpert.h>
20 static int hmac_dbrg_error(int val, __unused const char *msg) {
21 return val;
22 }
23 #else
24 static int hmac_dbrg_error(int val, const char *msg) {
25 if (msg) {
26 char buffer[1024];
27 snprintf(buffer, sizeof(buffer)-1, "Error: %s", msg);
28 cc_print(buffer, 0, NULL);
29 }
30 return val;
31 }
32 #endif
33
34 // Test vectors at:
35 // http://csrc.nist.gov/groups/STM/cavp/#05
36 // http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip
37 //
38
39 /*
40 This HMAC DBRG is described in:
41
42 SP 800-90 A Rev. 1 (2nd Draft)
43 DRAFT Recommendation for Random Number Generation Using Deterministic Random Bit Generators
44 April 2014
45
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
48
49 See in particular
50 - 10.1.2 HMAC_DRBG (p 45)
51 - B.2 HMAC_DRBGExample (p 83)
52
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
56 */
57
58
59
60 /*
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.
69 */
70
71 /*
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
76 too long”, −1)
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).
83 */
84
85 /*
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
91 bits.
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.
95 */
96
97 //
98 // Defines below based on 10.1, Table 2: Definitions for Hash-Based DRBG Mechanisms (p 39)
99 //
100
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
110
111 struct ccdrbg_nisthmac_state {
112 const struct ccdrbg_info *info;
113 size_t bytesLeft;
114 size_t reseed_counter;
115 size_t vsize;
116 size_t keysize;
117 uint8_t v[NH_MAX_OUTPUT_BLOCK_SIZE];
118 uint8_t key[NH_MAX_KEY_SIZE];
119 };
120
121 #ifdef DEBUGFOO
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);
125 }
126 #endif
127
128 /*
129 NIST SP 800-90A, Rev. 1 HMAC_DRBG April 2014, p 46
130
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.
135 Output:
136 1. K: The new value for Key.
137 2. V: The new value for V.
138
139 HMAC_DRBG Update Process:
140
141 1. K = HMAC (K, V || 0x00 || provided_data).
142 2. V=HMAC(K,V).
143 3. If (provided_data = Null), then return K and V.
144 4. K = HMAC (K, V || 0x01 || provided_data).
145 5. V=HMAC(K,V).
146 6. Return K and V.
147 */
148
149 // was: unsigned long providedDataLength, const void *providedData
150
151 /*
152 To handle the case where we have three strings that are concatenated,
153 we pass in three (ptr, len) pairs
154 */
155
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
160 )
161 {
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;
165
166 const unsigned char cZero = 0x00;
167 const unsigned char cOne = 0x01;
168 cchmac_ctx_decl(di->state_size, di->block_size, ctx);
169
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);
178
179 // 2. V=HMAC(K,V).
180 cchmac(di, state->keysize, state->key, state->vsize, state->v, state->v);
181
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)))
185 return 0;
186
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);
195
196 // 5. V=HMAC(K,V).
197 cchmac(di, state->keysize, state->key, state->vsize, state->v, state->v);
198
199 return 0;
200 }
201
202 /*
203 NIST SP 800-90A, Rev. 1 April 2014 B.2.2, p 84
204
205 HMAC_DRBG_Instantiate_algorithm (...):
206 Input: bitstring (entropy_input, personalization_string).
207 Output: bitstring (V, Key), integer reseed_counter.
208
209 Process:
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).
216 */
217
218 // This version does not do memory allocation
219
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)
224 {
225 // TODO: The NIST code passes nonce (i.e. HMAC key) to generate, but cc interface isn't set up that way
226
227 struct ccdrbg_nisthmac_state *state=(struct ccdrbg_nisthmac_state *)drbg;
228
229 // 1. seed_material = entropy_input || nonce || personalization_string.
230
231 // 2. Set Key to outlen bits of zeros.
232 cc_zero(state->keysize, state->key);
233
234 // 3. Set V to outlen/8 bytes of 0x01.
235 CC_MEMSET(state->v, 0x01, state->vsize);
236
237 // 4. (Key, V) = HMAC_DRBG_Update (seed_material, Key, V).
238 hmac_dbrg_update(drbg, entropyLength, entropy, nonceLength, nonce, psLength, ps);
239
240 // 5. reseed_counter = 1.
241 state->reseed_counter = 1;
242
243 return 0;
244 }
245
246 // In NIST terminology, the nonce is the HMAC key and ps is the personalization string
247
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)
252 {
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;
257 size_t min_entropy;
258
259 state->bytesLeft = 0;
260 state->info = info;
261 custom = state->info->custom;
262 di = custom->di;
263 state->vsize = di->output_size; // TODO: state_size? or output_size
264 state->keysize = di->output_size; // TODO: state size?
265
266 security_strength = NH_MAX_SECURITY_STRENGTH;
267
268 if (psLength > NH_MAX_PERSONALIZE_LEN) // "Personalization_string too long"
269 return hmac_dbrg_error(-1, "Personalization_string too long");
270
271 if (entropyLength > NH_MAX_ENTROPY_LEN) // Supplied too much entropy
272 return hmac_dbrg_error(-1, "Supplied too much entropy");
273
274 // 4. min_entropy = 1.5 × security_strength.
275 min_entropy = NH_REQUIRED_MIN_ENTROPY(security_strength);
276
277 // 7. (V, Key, reseed_counter) = HMAC_DRBG_Instantiate_algorithm (entropy_input, personalization_string).
278
279 hmac_dbrg_instantiate_algorithm(drbg, entropyLength, entropy, nonceLength, nonce, psLength, ps);
280
281 #ifdef DEBUGFOO
282 dumpState("Init: ", state);
283 #endif
284 return 0;
285 }
286
287 /*
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.
293
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):
297
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.
303
304 Output:
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.
309 */
310
311 static int reseed(struct ccdrbg_state *drbg,
312 unsigned long entropyLength, const void *entropy,
313 unsigned long inputlen, const void *input)
314 {
315 struct ccdrbg_nisthmac_state *state=(struct ccdrbg_nisthmac_state *)drbg;
316
317 int rx = hmac_dbrg_update(drbg, entropyLength, entropy, inputlen, input, 0, NULL);
318 state->reseed_counter = 1;
319
320 #ifdef DEBUGFOO
321 dumpState("Reseed: ", state);
322 #endif
323 return rx;
324 }
325
326 /*
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.
330
331 Process:
332 1. If (reseed_counter ≥ 10,000), then Return (“Reseed required”, Null, V, Key, reseed_counter).
333 2. temp = Null.
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).
341 */
342
343 static int generate(struct ccdrbg_state *drbg, unsigned long numBytes, void *outBytes,
344 unsigned long inputLen, const void *input)
345 {
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;
349
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");
353
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");
357
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);
361
362 // hmac_dbrg_generate_algorithm
363 char *outPtr = (char *) outBytes;
364 while (numBytes > 0) {
365 if (!state->bytesLeft) {
366 // 5. V=HMAC(K,V).
367 cchmac(di, state->keysize, state->key, state->vsize, state->v, state->v);
368 state->bytesLeft = di->output_size;//di->output_size; state->vsize
369 }
370 size_t outLength = numBytes > state->bytesLeft ? state->bytesLeft : numBytes;
371 memcpy(outPtr, state->v, outLength);
372 state->bytesLeft -= outLength;
373 outPtr += outLength;
374 numBytes -= outLength;
375 }
376
377 // 6. (Key, V) = HMAC_DRBG_Update (additional_input, Key, V).
378 hmac_dbrg_update(drbg, inputLen, input, 0, NULL, 0, NULL);
379
380 // 7. reseed_counter = reseed_counter + 1.
381 state->reseed_counter++;
382
383 #ifdef DEBUGFOO
384 dumpState("generate: ", state);
385 #endif
386
387 return 0;
388 }
389
390 static void done(struct ccdrbg_state *drbg)
391 {
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);
395 }
396
397 struct ccdrbg_info ccdrbg_nisthmac_info = {
398 .size = sizeof(struct ccdrbg_nisthmac_state) + sizeof(struct ccdrbg_nisthmac_custom),
399 .init = init,
400 .reseed = reseed,
401 .generate = generate,
402 .done = done,
403 .custom = NULL
404 };
405
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)
408 {
409 info->size = sizeof(struct ccdrbg_nisthmac_state) + sizeof(struct ccdrbg_nisthmac_custom);
410 info->init = init;
411 info->generate = generate;
412 info->reseed = reseed;
413 info->done = done;
414 info->custom = custom;
415 };
416