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