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