/** * Instantiate HMAC_DRBG * * @v hash Underlying hash algorithm * @v state HMAC_DRBG internal state to be initialised * @v entropy Entropy input * @v entropy_len Length of entropy input * @v personal Personalisation string * @v personal_len Length of personalisation string * * This is the HMAC_DRBG_Instantiate_algorithm function defined in ANS * X9.82 Part 3-2007 Section 10.2.2.2.3 (NIST SP 800-90 Section * 10.1.2.3). * * The nonce must be included within the entropy input (i.e. the * entropy input must contain at least 3/2 * security_strength bits of * entropy, as per ANS X9.82 Part 3-2007 Section 8.4.2 (NIST SP 800-90 * Section 8.6.7). * * The key, value and reseed counter are updated in-place within the * HMAC_DRBG internal state. */ void hmac_drbg_instantiate ( struct digest_algorithm *hash, struct hmac_drbg_state *state, const void *entropy, size_t entropy_len, const void *personal, size_t personal_len ){ size_t out_len = hash->digestsize; DBGC ( state, "HMAC_DRBG_%s %p instantiate\n", hash->name, state ); /* Sanity checks */ assert ( hash != NULL ); assert ( state != NULL ); assert ( entropy != NULL ); assert ( ( personal != NULL ) || ( personal_len == 0 ) ); /* 1. seed_material = entropy_input || nonce || * personalisation_string */ /* 2. Key = 0x00 00..00 */ memset ( state->key, 0x00, out_len ); /* 3. V = 0x01 01...01 */ memset ( state->value, 0x01, out_len ); /* 4. ( Key, V ) = HMAC_DBRG_Update ( seed_material, Key, V ) * 5. reseed_counter = 1 * 6. Return V, Key and reseed_counter as the * initial_working_state */ hmac_drbg_reseed ( hash, state, entropy, entropy_len, personal, personal_len ); }
/* * 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 ); }
/* * HMAC_DRBG initialisation (10.1.2.3 + 9.1) */ SSL_ROM_TEXT_SECTION int hmac_drbg_init( hmac_drbg_context *ctx, const md_info_t * md_info, int (*f_entropy)(void *, unsigned char *, size_t), void *p_entropy, const unsigned char *custom, size_t len ) { int ret; size_t entropy_len; 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 ); ctx->f_entropy = f_entropy; ctx->p_entropy = p_entropy; ctx->reseed_interval = POLARSSL_HMAC_DRBG_RESEED_INTERVAL; /* * See SP800-57 5.6.1 (p. 65-66) for the security strength provided by * each hash function, then according to SP800-90A rev1 10.1 table 2, * min_entropy_len (in bits) is security_strength. * * (This also matches the sizes used in the NIST test vectors.) */ entropy_len = md_info->size <= 20 ? 16 : /* 160-bits hash -> 128 bits */ md_info->size <= 28 ? 24 : /* 224-bits hash -> 192 bits */ 32; /* better (256+) -> 256 bits */ /* * For initialisation, use more entropy to emulate a nonce * (Again, matches test vectors.) */ ctx->entropy_len = entropy_len * 3 / 2; if( ( ret = hmac_drbg_reseed( ctx, custom, len ) ) != 0 ) return( ret ); ctx->entropy_len = entropy_len; return( 0 ); }
/* * Checkup routine for HMAC_DRBG with SHA-1 */ SSL_ROM_TEXT_SECTION int hmac_drbg_self_test( int verbose ) { hmac_drbg_context ctx; unsigned char buf[OUTPUT_LEN]; const md_info_t *md_info = md_info_from_type( POLARSSL_MD_SHA1 ); /* * PR = True */ if( verbose != 0 ) polarssl_printf( " HMAC_DRBG (PR = True) : " ); test_offset = 0; CHK( hmac_drbg_init( &ctx, md_info, hmac_drbg_self_test_entropy, entropy_pr, NULL, 0 ) ); hmac_drbg_set_prediction_resistance( &ctx, POLARSSL_HMAC_DRBG_PR_ON ); CHK( hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) ); CHK( hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) ); CHK( memcmp( buf, result_pr, OUTPUT_LEN ) ); hmac_drbg_free( &ctx ); if( verbose != 0 ) polarssl_printf( "passed\n" ); /* * PR = False */ if( verbose != 0 ) polarssl_printf( " HMAC_DRBG (PR = False) : " ); test_offset = 0; CHK( hmac_drbg_init( &ctx, md_info, hmac_drbg_self_test_entropy, entropy_nopr, NULL, 0 ) ); CHK( hmac_drbg_reseed( &ctx, NULL, 0 ) ); CHK( hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) ); CHK( hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) ); CHK( memcmp( buf, result_nopr, OUTPUT_LEN ) ); hmac_drbg_free( &ctx ); if( verbose != 0 ) polarssl_printf( "passed\n" ); if( verbose != 0 ) polarssl_printf( "\n" ); return( 0 ); }