Merge pull request #2894 from gilles-peskine-arm/drbg-set_entropy_len-2.16
Backport 2.16: Allow xxx_drbg_set_entropy_len before xxx_drbg_seed
diff --git a/ChangeLog b/ChangeLog
index c92e429..2f2afb7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -6,6 +6,10 @@
* Remove redundant line for getting the bitlen of a bignum, since the variable
holding the returned value is overwritten a line after.
Found by irwir in #2377.
+ * Support mbedtls_hmac_drbg_set_entropy_len() and
+ mbedtls_ctr_drbg_set_entropy_len() before the DRBG is seeded. Before,
+ the initial seeding always reset the entropy length to the compile-time
+ default.
Changes
* Add unit tests for AES-GCM when called through mbedtls_cipher_auth_xxx()
diff --git a/include/mbedtls/ctr_drbg.h b/include/mbedtls/ctr_drbg.h
index 766e647..e0b5ed9 100644
--- a/include/mbedtls/ctr_drbg.h
+++ b/include/mbedtls/ctr_drbg.h
@@ -214,11 +214,8 @@
* with mbedtls_entropy_init() (which registers the platform's default
* entropy sources).
*
- * \p f_entropy is always called with a buffer size equal to the entropy
- * length. The entropy length is initially #MBEDTLS_CTR_DRBG_ENTROPY_LEN
- * and this value is always used for the initial seeding. You can change
- * the entropy length for subsequent seeding by calling
- * mbedtls_ctr_drbg_set_entropy_len() after this function.
+ * The entropy length is #MBEDTLS_CTR_DRBG_ENTROPY_LEN by default.
+ * You can override it by calling mbedtls_ctr_drbg_set_entropy_len().
*
* You can provide a personalization string in addition to the
* entropy source, to make this instantiation as unique as possible.
@@ -252,9 +249,18 @@
#endif
/**
* \param ctx The CTR_DRBG context to seed.
+ * It must have been initialized with
+ * mbedtls_ctr_drbg_init().
+ * After a successful call to mbedtls_ctr_drbg_seed(),
+ * you may not call mbedtls_ctr_drbg_seed() again on
+ * the same context unless you call
+ * mbedtls_ctr_drbg_free() and mbedtls_ctr_drbg_init()
+ * again first.
* \param f_entropy The entropy callback, taking as arguments the
* \p p_entropy context, the buffer to fill, and the
* length of the buffer.
+ * \p f_entropy is always called with a buffer size
+ * equal to the entropy length.
* \param p_entropy The entropy context to pass to \p f_entropy.
* \param custom The personalization string.
* This can be \c NULL, in which case the personalization
@@ -298,15 +304,10 @@
/**
* \brief This function sets the amount of entropy grabbed on each
- * subsequent reseed.
+ * seed or reseed.
*
* The default value is #MBEDTLS_CTR_DRBG_ENTROPY_LEN.
*
- * \note mbedtls_ctr_drbg_seed() always sets the entropy length
- * to #MBEDTLS_CTR_DRBG_ENTROPY_LEN, so this function
- * only has an effect when it is called after
- * mbedtls_ctr_drbg_seed().
- *
* \note The security strength of CTR_DRBG is bounded by the
* entropy length. Thus:
* - When using AES-256
diff --git a/include/mbedtls/hmac_drbg.h b/include/mbedtls/hmac_drbg.h
index 20b29d9..7931c22 100644
--- a/include/mbedtls/hmac_drbg.h
+++ b/include/mbedtls/hmac_drbg.h
@@ -139,13 +139,11 @@
* Note that SHA-256 is just as efficient as SHA-224.
* The security strength can be reduced if a smaller
* entropy length is set with
- * mbedtls_hmac_drbg_set_entropy_len() afterwards.
+ * mbedtls_hmac_drbg_set_entropy_len().
*
- * \note The entropy length for the initial seeding is
- * the security strength (converted from bits to bytes).
- * You can set a different entropy length for subsequent
- * seeding by calling mbedtls_hmac_drbg_set_entropy_len()
- * after this function.
+ * \note The default entropy length is the security strength
+ * (converted from bits to bytes). You can override
+ * it by calling mbedtls_hmac_drbg_set_entropy_len().
*
* \note During the initial seeding, this function calls
* the entropy source to obtain a nonce
@@ -224,14 +222,9 @@
/**
* \brief This function sets the amount of entropy grabbed on each
- * reseed.
+ * seed or reseed.
*
- * The default value is set by mbedtls_hmac_drbg_seed().
- *
- * \note mbedtls_hmac_drbg_seed() always sets the entropy length
- * to the default value based on the chosen MD algorithm,
- * so this function only has an effect if it is called
- * after mbedtls_hmac_drbg_seed().
+ * See the documentation of mbedtls_hmac_drbg_seed() for the default value.
*
* \param ctx The HMAC_DRBG context.
* \param len The amount of entropy to grab, in bytes.
diff --git a/library/ctr_drbg.c b/library/ctr_drbg.c
index fb12157..32b34e4 100644
--- a/library/ctr_drbg.c
+++ b/library/ctr_drbg.c
@@ -62,68 +62,6 @@
#endif
}
-/*
- * Non-public function wrapped by mbedtls_ctr_drbg_seed(). Necessary to allow
- * NIST tests to succeed (which require known length fixed entropy)
- */
-/* CTR_DRBG_Instantiate with derivation function (SP 800-90A §10.2.1.3.2)
- * mbedtls_ctr_drbg_seed_entropy_len(ctx, f_entropy, p_entropy,
- * custom, len, entropy_len)
- * implements
- * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string,
- * security_strength) -> initial_working_state
- * with inputs
- * custom[:len] = nonce || personalization_string
- * where entropy_input comes from f_entropy for entropy_len bytes
- * and with outputs
- * ctx = initial_working_state
- */
-int mbedtls_ctr_drbg_seed_entropy_len(
- mbedtls_ctr_drbg_context *ctx,
- int (*f_entropy)(void *, unsigned char *, size_t),
- void *p_entropy,
- const unsigned char *custom,
- size_t len,
- size_t entropy_len )
-{
- int ret;
- unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
-
- memset( key, 0, MBEDTLS_CTR_DRBG_KEYSIZE );
-
- mbedtls_aes_init( &ctx->aes_ctx );
-
- ctx->f_entropy = f_entropy;
- ctx->p_entropy = p_entropy;
-
- ctx->entropy_len = entropy_len;
- ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
-
- /*
- * Initialize with an empty key
- */
- if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, key, MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
- {
- return( ret );
- }
-
- if( ( ret = mbedtls_ctr_drbg_reseed( ctx, custom, len ) ) != 0 )
- {
- return( ret );
- }
- return( 0 );
-}
-
-int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx,
- int (*f_entropy)(void *, unsigned char *, size_t),
- void *p_entropy,
- const unsigned char *custom,
- size_t len )
-{
- return( mbedtls_ctr_drbg_seed_entropy_len( ctx, f_entropy, p_entropy, custom, len,
- MBEDTLS_CTR_DRBG_ENTROPY_LEN ) );
-}
-
void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx )
{
if( ctx == NULL )
@@ -427,6 +365,63 @@
return( ret );
}
+/* CTR_DRBG_Instantiate with derivation function (SP 800-90A §10.2.1.3.2)
+ * mbedtls_ctr_drbg_seed(ctx, f_entropy, p_entropy, custom, len)
+ * implements
+ * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string,
+ * security_strength) -> initial_working_state
+ * with inputs
+ * custom[:len] = nonce || personalization_string
+ * where entropy_input comes from f_entropy for ctx->entropy_len bytes
+ * and with outputs
+ * ctx = initial_working_state
+ */
+int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx,
+ int (*f_entropy)(void *, unsigned char *, size_t),
+ void *p_entropy,
+ const unsigned char *custom,
+ size_t len )
+{
+ int ret;
+ unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
+
+ memset( key, 0, MBEDTLS_CTR_DRBG_KEYSIZE );
+
+ mbedtls_aes_init( &ctx->aes_ctx );
+
+ ctx->f_entropy = f_entropy;
+ ctx->p_entropy = p_entropy;
+
+ if( ctx->entropy_len == 0 )
+ ctx->entropy_len = MBEDTLS_CTR_DRBG_ENTROPY_LEN;
+ ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
+
+ /*
+ * Initialize with an empty key
+ */
+ if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, key, MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ if( ( ret = mbedtls_ctr_drbg_reseed( ctx, custom, len ) ) != 0 )
+ {
+ return( ret );
+ }
+ return( 0 );
+}
+
+/* Backward compatibility wrapper */
+int mbedtls_ctr_drbg_seed_entropy_len(
+ mbedtls_ctr_drbg_context *ctx,
+ int (*f_entropy)(void *, unsigned char *, size_t), void *p_entropy,
+ const unsigned char *custom, size_t len,
+ size_t entropy_len )
+{
+ mbedtls_ctr_drbg_set_entropy_len( ctx, entropy_len );
+ return( mbedtls_ctr_drbg_seed( ctx, f_entropy, p_entropy, custom, len ) );
+}
+
/* CTR_DRBG_Generate with derivation function (SP 800-90A §10.2.1.5.2)
* mbedtls_ctr_drbg_random_with_add(ctx, output, output_len, additional, add_len)
* implements
@@ -678,8 +673,11 @@
mbedtls_printf( " CTR_DRBG (PR = TRUE) : " );
test_offset = 0;
- CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy,
- (void *) entropy_source_pr, nonce_pers_pr, 16, 32 ) );
+ mbedtls_ctr_drbg_set_entropy_len( &ctx, 32 );
+ CHK( mbedtls_ctr_drbg_seed( &ctx,
+ ctr_drbg_self_test_entropy,
+ (void *) entropy_source_pr,
+ nonce_pers_pr, 16 ) );
mbedtls_ctr_drbg_set_prediction_resistance( &ctx, MBEDTLS_CTR_DRBG_PR_ON );
CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) );
CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) );
@@ -699,8 +697,11 @@
mbedtls_ctr_drbg_init( &ctx );
test_offset = 0;
- CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy,
- (void *) entropy_source_nopr, nonce_pers_nopr, 16, 32 ) );
+ mbedtls_ctr_drbg_set_entropy_len( &ctx, 32 );
+ CHK( mbedtls_ctr_drbg_seed( &ctx,
+ ctr_drbg_self_test_entropy,
+ (void *) entropy_source_nopr,
+ nonce_pers_nopr, 16 ) );
CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) );
CHK( mbedtls_ctr_drbg_reseed( &ctx, NULL, 0 ) );
CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) );
diff --git a/library/hmac_drbg.c b/library/hmac_drbg.c
index 50d88bd..284c9b4 100644
--- a/library/hmac_drbg.c
+++ b/library/hmac_drbg.c
@@ -273,16 +273,19 @@
ctx->reseed_interval = MBEDTLS_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.)
- */
- 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 */
+ if( ctx->entropy_len == 0 )
+ {
+ /*
+ * 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 */
+ }
if( ( ret = hmac_drbg_reseed_core( ctx, custom, len,
1 /* add nonce */ ) ) != 0 )
@@ -303,7 +306,7 @@
}
/*
- * Set entropy length grabbed for reseeds
+ * Set entropy length grabbed for seeding
*/
void mbedtls_hmac_drbg_set_entropy_len( mbedtls_hmac_drbg_context *ctx, size_t len )
{
diff --git a/programs/test/benchmark.c b/programs/test/benchmark.c
index 2b86566..9c06d07 100644
--- a/programs/test/benchmark.c
+++ b/programs/test/benchmark.c
@@ -674,12 +674,13 @@
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ctr_drbg_init( &ctr_drbg );
-
if( mbedtls_ctr_drbg_seed( &ctr_drbg, myrand, NULL, NULL, 0 ) != 0 )
mbedtls_exit(1);
TIME_AND_TSC( "CTR_DRBG (NOPR)",
mbedtls_ctr_drbg_random( &ctr_drbg, buf, BUFSIZE ) );
+ mbedtls_ctr_drbg_free( &ctr_drbg );
+ mbedtls_ctr_drbg_init( &ctr_drbg );
if( mbedtls_ctr_drbg_seed( &ctr_drbg, myrand, NULL, NULL, 0 ) != 0 )
mbedtls_exit(1);
mbedtls_ctr_drbg_set_prediction_resistance( &ctr_drbg, MBEDTLS_CTR_DRBG_PR_ON );
diff --git a/tests/suites/test_suite_ctr_drbg.function b/tests/suites/test_suite_ctr_drbg.function
index 4a97826..01050d9 100644
--- a/tests/suites/test_suite_ctr_drbg.function
+++ b/tests/suites/test_suite_ctr_drbg.function
@@ -44,11 +44,11 @@
/* CTR_DRBG_Instantiate(entropy[:entropy->len], nonce, perso, <ignored>)
* where nonce||perso = nonce[nonce->len] */
- TEST_ASSERT( mbedtls_ctr_drbg_seed_entropy_len(
+ mbedtls_ctr_drbg_set_entropy_len( &ctx, entropy_chunk_len );
+ TEST_ASSERT( mbedtls_ctr_drbg_seed(
&ctx,
mbedtls_test_entropy_func, entropy->x,
- nonce->x, nonce->len,
- entropy_chunk_len ) == 0 );
+ nonce->x, nonce->len ) == 0 );
if( reseed_mode == RESEED_ALWAYS )
mbedtls_ctr_drbg_set_prediction_resistance(
&ctx,