ARMmbed

HMAC DRBG incorrect output

I’m trying to implement HMAC DRBG and I’m using CTR_DRBG as a reference.

My calls are as follows:

mbedtls_hmac_drbg_seed( &hmac_ctx, md_info, mbedtls_test_entropy_func, entropy_inputs, nonce_pers, strlen(nonce_pers) );
mbedtls_hmac_drbg_set_prediction_resistance(&hmac_ctx, MBEDTLS_CTR_DRBG_PR_ON );
mbedtls_hmac_drbg_random_with_add(&hmac_ctx, result, resultLen, addInput1, addInputLength);
mbedtls_hmac_drbg_random_with_add(&hmac_ctx, result, resultLen, addInput2, addInputLength);

I’ve printed the offset of index used for mbedtls_test_entropy_func() after every call. Here are the values:

**For SHA-1:**
md size = 20
Before mbedtls_hmac_drbg_seed() : 0
After mbedtls_hmac_drbg_seed() : 24
After mbedtls_hmac_drbg_random_with_add 1() : 40

========================================

**For SHA-256:**
md size = 32
Before mbedtls_hmac_drbg_seed() : 0
After mbedtls_hmac_drbg_seed() : 48
After mbedtls_hmac_drbg_random_with_add 1() : 80

Within 1 request file I’ve tests with SHA-1. SHA-256 and SHA-512. So I should be able to test any variant of SHA.
The #defines in config file are shown below:

#define MBEDTLS_SHA1_C
#define MBEDTLS_ENTROPY_FORCE_SHA256
#define MBEDTLS_SHA512_C

The offsets don’t seem right to me. I’m using the same mbedtls_test_entropy_func() as I used for CTR_DRBG ( I’ve replicated mbedtls_test_entropy_func () from ctr_drbg_validate_internal ()).

Hi @athorath

Thank you for your question!

Are you using the hmac_drbg as reference for your tests? If so, note that the entropy_context used should also change.

The entropy length in hmac_drbg is not identical as in ctr_drbg.

As you can see from the code, calling mbedtls_hmac_drbg_seed() will have the following definitions:

    /*
     * 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.)
     */
    ctx->entropy_len = md_size <= 20 ? 16 : /* 160-bits hash -> 128 bits */
                       md_size <= 28 ? 24 : /* 224-bits hash -> 192 bits */
                       32;  /* better (256+) -> 256 bits */

Which calls hmac_drbg_reseed_core() with use_nonce = 1 , so it calls f_entropy twice:

    if( ( ret = ctx->f_entropy( ctx->p_entropy,
                                seed, ctx->entropy_len ) ) != 0 )

and

     * from the entropy source. See Sect 8.6.7 in SP800-90A. */
    if( use_nonce )
    {
        /* Note: We don't merge the two calls to f_entropy() in order
         *       to avoid requesting too much entropy from f_entropy()
         *       at once. Specifically, if the underlying digest is not
         *       SHA-1, 3 / 2 * entropy_len is at least 36 Bytes, which
         *       is larger than the maximum of 32 Bytes that our own
         *       entropy source implementation can emit in a single
         *       call in configurations disabling SHA-512. */
        if( ( ret = ctx->f_entropy( ctx->p_entropy,
                                    seed + seedlen,
                                    ctx->entropy_len / 2 ) ) != 0 )

so, for SHA1 hmac_drbg, your offset should be 16 + 8 = 24 , and for SHA256, it should be 32 + 16 = 48 , as the results you are seeing. The reasoning for these values are in the standards mentioned in the comments.
Regards,
Mbed TLS Support
Ron

@roneld01: Thanks for the wonderful explanation.
Now I’ve updated my code to look like hmac_drbg you mentioned in the comment above. I’m using hmac_drbg_pr() as my reference.

My mbedtls_test_entropy_func() now matches whatever is in that file. Apart from that, all my calls match hmac_drbg_pr() from the file you mentioned.

    mbedtls_hmac_drbg_init (&hmac_ctx);
    md_info = mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 );
    p_entropy.p = entropy_inputs;
    p_entropy.len = strlen(entropy_inputs);

    rc = mbedtls_hmac_drbg_seed( &hmac_ctx, md_info, mbedtls_test_entropy_func, entropy_inputs, nonce_pers, strlen(nonce_pers) );
    
    mbedtls_hmac_drbg_set_prediction_resistance(&hmac_ctx, MBEDTLS_HMAC_DRBG_PR_ON );
    
    rc = mbedtls_hmac_drbg_random_with_add(&hmac_ctx, result, resultLen, addInput1, addInputLength);
    rc = mbedtls_hmac_drbg_random_with_add(&hmac_ctx, result, resultLen, addInput2, addInputLength);

It exactly matches hmac_drbg_pr(). However, I get an error in entropy function at line memcpy( buf, ctx->p, len );

I’ve printed the values:

(gdb) print len
$2 = 24
(gdb) print ctx->len
$3 = 11840012698478436789

ctx->len seems to be wrong. May be that’s what is causing the error?

entropy_ctx *ctx = (entropy_ctx *) data;
This line is not assigning anything to ctx->len is it?
In mbedtls_test_entropy_func() we just declare ctx of type entropy_ctx and assign data to it but nothing is assigned to ctx->len.

Also wanted to check one more thing.
Can you please confirm what’s the answer you should be getting while using the below inputs (listed what responses I get with OpenSSL and mbedTLS):

[SHA-1]
[PredictionResistance = True]
[EntropyInputLen = 128]
[NonceLen = 64]
[PersonalizationStringLen = 0]
[AdditionalInputLen = 0]
[ReturnedBitsLen = 640]

COUNT = 0
EntropyInput = 6878f9ea4ff71310b5e1eb74d12c50a4
Nonce = 9edc884c73de0637
PersonalizationString =
AdditionalInput =
EntropyInputPR = c924feaafcfacaaf76e558351963eddc
AdditionalInput =
EntropyInputPR = a9704c677723b480c10c878636167c0d
mbedtls_ReturnedBits = 459a3ea43f958d3000edf286e718238049740011fe061dc55ccde3cd575170c508ebc78178f79a926344d074fb4d5e19e89f4fc4c388f851ecd8e2a154f6ef3939dbd5e481095cce614c9aa2399987c3
openssl_ReturnedBits = f6a4a5e37fd88c6a444346d035d5a50b4e00522e28cc0aad9893cb1ca03fcb8474142bf3f40e5c391e81826240420f22415ef7bf9142add94925d53d93078927b00c1fe0b20a9387facd95fcf9ab541a