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>
20static int hmac_dbrg_error(int val, __unused const char *msg) {
21	return val;
22}
23#else
24static 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
111struct 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
122static 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
156static 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
220static 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
248static 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
311static 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
343static 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
390static 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
397struct 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 */
407void 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
417