/* * HMAC_DRBG random function with optional additional data: * 10.1.2.5 (arabic) + 9.3 (Roman) */ SSL_ROM_TEXT_SECTION int hmac_drbg_random_with_add( void *p_rng, unsigned char *output, size_t out_len, const unsigned char *additional, size_t add_len ) { int ret; hmac_drbg_context *ctx = (hmac_drbg_context *) p_rng; size_t md_len = md_get_size( ctx->md_ctx.md_info ); size_t left = out_len; unsigned char *out = output; /* II. Check request length */ if( out_len > POLARSSL_HMAC_DRBG_MAX_REQUEST ) return( POLARSSL_ERR_HMAC_DRBG_REQUEST_TOO_BIG ); /* III. Check input length */ if( add_len > POLARSSL_HMAC_DRBG_MAX_INPUT ) return( POLARSSL_ERR_HMAC_DRBG_INPUT_TOO_BIG ); /* 1. (aka VII and IX) Check reseed counter and PR */ if( ctx->f_entropy != NULL && /* For no-reseeding instances */ ( ctx->prediction_resistance == POLARSSL_HMAC_DRBG_PR_ON || ctx->reseed_counter > ctx->reseed_interval ) ) { if( ( ret = hmac_drbg_reseed( ctx, additional, add_len ) ) != 0 ) return( ret ); add_len = 0; /* VII.4 */ } /* 2. Use additional data if any */ if( additional != NULL && add_len != 0 ) hmac_drbg_update( ctx, additional, add_len ); /* 3, 4, 5. Generate bytes */ while( left != 0 ) { size_t use_len = left > md_len ? md_len : left; md_hmac_reset( &ctx->md_ctx ); md_hmac_update( &ctx->md_ctx, ctx->V, md_len ); md_hmac_finish( &ctx->md_ctx, ctx->V ); memcpy( out, ctx->V, use_len ); out += use_len; left -= use_len; } /* 6. Update */ hmac_drbg_update( ctx, additional, add_len ); /* 7. Update reseed counter */ ctx->reseed_counter++; /* 8. Done */ return( 0 ); }
/* * Simplified HMAC_DRBG initialisation (for use with deterministic ECDSA) */ SSL_ROM_TEXT_SECTION int hmac_drbg_init_buf( hmac_drbg_context *ctx, const md_info_t * md_info, const unsigned char *data, size_t data_len ) { int ret; memset( ctx, 0, sizeof( hmac_drbg_context ) ); md_init( &ctx->md_ctx ); if( ( ret = md_init_ctx( &ctx->md_ctx, md_info ) ) != 0 ) return( ret ); /* * Set initial working state. * Use the V memory location, which is currently all 0, to initialize the * MD context with an all-zero key. Then set V to its initial value. */ md_hmac_starts( &ctx->md_ctx, ctx->V, md_info->size ); memset( ctx->V, 0x01, md_info->size ); hmac_drbg_update( ctx, data, data_len ); return( 0 ); }
SSL_ROM_TEXT_SECTION int hmac_drbg_update_seed_file( hmac_drbg_context *ctx, const char *path ) { FILE *f; size_t n; unsigned char buf[ POLARSSL_HMAC_DRBG_MAX_INPUT ]; if( ( f = fopen( path, "rb" ) ) == NULL ) return( POLARSSL_ERR_HMAC_DRBG_FILE_IO_ERROR ); fseek( f, 0, SEEK_END ); n = (size_t) ftell( f ); fseek( f, 0, SEEK_SET ); if( n > POLARSSL_HMAC_DRBG_MAX_INPUT ) { fclose( f ); return( POLARSSL_ERR_HMAC_DRBG_INPUT_TOO_BIG ); } if( fread( buf, 1, n, f ) != n ) { fclose( f ); return( POLARSSL_ERR_HMAC_DRBG_FILE_IO_ERROR ); } fclose( f ); hmac_drbg_update( ctx, buf, n ); return( hmac_drbg_write_seed_file( ctx, path ) ); }
/** * Reseed HMAC_DRBG * * @v hash Underlying hash algorithm * @v state HMAC_DRBG internal state * @v entropy Entropy input * @v entropy_len Length of entropy input * @v additional Additional input * @v additional_len Length of additional input * * This is the HMAC_DRBG_Reseed_algorithm function defined in ANS X9.82 * Part 3-2007 Section 10.2.2.2.4 (NIST SP 800-90 Section 10.1.2.4). * * The key, value and reseed counter are updated in-place within the * HMAC_DRBG internal state. */ void hmac_drbg_reseed ( struct digest_algorithm *hash, struct hmac_drbg_state *state, const void *entropy, size_t entropy_len, const void *additional, size_t additional_len ) { uint8_t seed_material[ entropy_len + additional_len ]; DBGC ( state, "HMAC_DRBG_%s %p (re)seed\n", hash->name, state ); /* Sanity checks */ assert ( hash != NULL ); assert ( state != NULL ); assert ( entropy != NULL ); assert ( ( additional != NULL ) || ( additional_len == 0 ) ); /* 1. seed_material = entropy_input || additional_input */ memcpy ( seed_material, entropy, entropy_len ); memcpy ( ( seed_material + entropy_len ), additional, additional_len ); DBGC ( state, "HMAC_DRBG_%s %p seed material :\n", hash->name, state ); DBGC_HDA ( state, 0, seed_material, sizeof ( seed_material ) ); /* 2. ( Key, V ) = HMAC_DBRG_Update ( seed_material, Key, V ) */ hmac_drbg_update ( hash, state, seed_material, sizeof ( seed_material ) ); /* 3. reseed_counter = 1 */ state->reseed_counter = 1; /* 4. Return V, Key and reseed_counter as the new_working_state */ }
/* * HMAC_DRBG reseeding: 10.1.2.4 (arabic) + 9.2 (Roman) */ SSL_ROM_TEXT_SECTION int hmac_drbg_reseed( hmac_drbg_context *ctx, const unsigned char *additional, size_t len ) { unsigned char seed[POLARSSL_HMAC_DRBG_MAX_SEED_INPUT]; size_t seedlen; /* III. Check input length */ if( len > POLARSSL_HMAC_DRBG_MAX_INPUT || ctx->entropy_len + len > POLARSSL_HMAC_DRBG_MAX_SEED_INPUT ) { return( POLARSSL_ERR_HMAC_DRBG_INPUT_TOO_BIG ); } memset( seed, 0, POLARSSL_HMAC_DRBG_MAX_SEED_INPUT ); /* IV. Gather entropy_len bytes of entropy for the seed */ if( ctx->f_entropy( ctx->p_entropy, seed, ctx->entropy_len ) != 0 ) return( POLARSSL_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED ); seedlen = ctx->entropy_len; /* 1. Concatenate entropy and additional data if any */ if( additional != NULL && len != 0 ) { memcpy( seed + seedlen, additional, len ); seedlen += len; } /* 2. Update state */ hmac_drbg_update( ctx, seed, seedlen ); /* 3. Reset reseed_counter */ ctx->reseed_counter = 1; /* 4. Done */ return( 0 ); }
/** * Generate pseudorandom bits using HMAC_DRBG * * @v hash Underlying hash algorithm * @v state HMAC_DRBG internal state * @v additional Additional input * @v additional_len Length of additional input * @v data Output buffer * @v len Length of output buffer * @ret rc Return status code * * This is the HMAC_DRBG_Generate_algorithm function defined in ANS X9.82 * Part 3-2007 Section 10.2.2.2.5 (NIST SP 800-90 Section 10.1.2.5). * * Requests must be for an integral number of bytes. * * The key, value and reseed counter are updated in-place within the * HMAC_DRBG internal state. * * Note that the only permitted error is "reseed required". */ int hmac_drbg_generate ( struct digest_algorithm *hash, struct hmac_drbg_state *state, const void *additional, size_t additional_len, void *data, size_t len ) { size_t out_len = hash->digestsize; void *orig_data = data; size_t orig_len = len; size_t frag_len; DBGC ( state, "HMAC_DRBG_%s %p generate\n", hash->name, state ); /* Sanity checks */ assert ( hash != NULL ); assert ( state != NULL ); assert ( data != NULL ); assert ( ( additional != NULL ) || ( additional_len == 0 ) ); /* 1. If reseed_counter > reseed_interval, then return an * indication that a reseed is required */ if ( state->reseed_counter > HMAC_DRBG_RESEED_INTERVAL ) { DBGC ( state, "HMAC_DRBG_%s %p reseed interval exceeded\n", hash->name, state ); return -ESTALE; } /* 2. If additional_input != Null, then * ( Key, V ) = HMAC_DRBG_Update ( additional_input, Key, V ) */ if ( additional_len ) hmac_drbg_update ( hash, state, additional, additional_len ); /* 3. temp = Null * 4. While ( len ( temp ) < requested_number_of_bits ) do: */ while ( len ) { /* 4.1 V = HMAC ( Key, V ) */ hmac_drbg_update_value ( hash, state ); /* 4.2. temp = temp || V * 5. returned_bits = Leftmost requested_number_of_bits * of temp */ frag_len = len; if ( frag_len > out_len ) frag_len = out_len; memcpy ( data, state->value, frag_len ); data += frag_len; len -= frag_len; } /* 6. ( Key, V ) = HMAC_DRBG_Update ( additional_input, Key, V ) */ hmac_drbg_update ( hash, state, additional, additional_len ); /* 7. reseed_counter = reseed_counter + 1 */ state->reseed_counter++; DBGC ( state, "HMAC_DRBG_%s %p generated :\n", hash->name, state ); DBGC_HDA ( state, 0, orig_data, orig_len ); /* 8. Return SUCCESS, returned_bits, and the new values of * Key, V and reseed_counter as the new_working_state */ return 0; }