Merge pull request #305 from gilles-peskine-arm/ctr_drbg-grab_nonce_from_entropy-set_nonce_length

CTR_DRBG: grab a nonce from the entropy source if needed
This commit is contained in:
Gilles Peskine 2019-11-04 10:39:42 +01:00 committed by GitHub
commit 22589f0a72
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 317 additions and 125 deletions

View file

@ -12,30 +12,14 @@
* The Mbed TLS implementation of CTR_DRBG uses AES-256 (default) or AES-128
* (if \c MBEDTLS_CTR_DRBG_USE_128_BIT_KEY is enabled at compile time)
* as the underlying block cipher, with a derivation function.
* The initial seeding grabs #MBEDTLS_CTR_DRBG_ENTROPY_LEN bytes of entropy.
* See the documentation of mbedtls_ctr_drbg_seed() for more details.
*
* Based on NIST SP 800-90A §10.2.1 table 3 and NIST SP 800-57 part 1 table 2,
* here are the security strengths achieved in typical configuration:
* - 256 bits under the default configuration of the library, with AES-256
* and with #MBEDTLS_CTR_DRBG_ENTROPY_LEN set to 48 or more.
* - 256 bits if AES-256 is used, #MBEDTLS_CTR_DRBG_ENTROPY_LEN is set
* to 32 or more, and the DRBG is initialized with an explicit
* nonce in the \c custom parameter to mbedtls_ctr_drbg_seed().
* - 128 bits if AES-256 is used but #MBEDTLS_CTR_DRBG_ENTROPY_LEN is
* between 24 and 47 and the DRBG is not initialized with an explicit
* nonce (see mbedtls_ctr_drbg_seed()).
* - 128 bits if AES-128 is used (\c MBEDTLS_CTR_DRBG_USE_128_BIT_KEY enabled)
* and #MBEDTLS_CTR_DRBG_ENTROPY_LEN is set to 24 or more (which is
* always the case unless it is explicitly set to a different value
* in config.h).
*
* Note that the value of #MBEDTLS_CTR_DRBG_ENTROPY_LEN defaults to:
* - \c 48 if the module \c MBEDTLS_SHA512_C is enabled and the symbol
* \c MBEDTLS_ENTROPY_FORCE_SHA256 is disabled at compile time.
* This is the default configuration of the library.
* - \c 32 if the module \c MBEDTLS_SHA512_C is disabled at compile time.
* - \c 32 if \c MBEDTLS_ENTROPY_FORCE_SHA256 is enabled at compile time.
* The security strength as defined in NIST SP 800-90A is
* 128 bits when AES-128 is used (\c MBEDTLS_CTR_DRBG_USE_128_BIT_KEY enabled)
* and 256 bits otherwise, provided that #MBEDTLS_CTR_DRBG_ENTROPY_LEN is
* kept at its default value (and not overridden in config.h) and that the
* DRBG instance is set up with default parameters.
* See the documentation of mbedtls_ctr_drbg_seed() for more
* information.
*/
/*
* Copyright (C) 2006-2019, Arm Limited (or its affiliates), All Rights Reserved
@ -163,20 +147,47 @@
extern "C" {
#endif
#if MBEDTLS_CTR_DRBG_ENTROPY_LEN >= MBEDTLS_CTR_DRBG_KEYSIZE * 3 / 2
/** The default length of the nonce read from the entropy source.
*
* This is \c 0 because a single read from the entropy source is sufficient
* to include a nonce.
* See the documentation of mbedtls_ctr_drbg_seed() for more information.
*/
#define MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN 0
#else
/** The default length of the nonce read from the entropy source.
*
* This is half of the default entropy length because a single read from
* the entropy source does not provide enough material to form a nonce.
* See the documentation of mbedtls_ctr_drbg_seed() for more information.
*/
#define MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN ( MBEDTLS_CTR_DRBG_ENTROPY_LEN + 1 ) / 2
#endif
/**
* \brief The CTR_DRBG context structure.
*/
typedef struct mbedtls_ctr_drbg_context
{
unsigned char counter[16]; /*!< The counter (V). */
int reseed_counter; /*!< The reseed counter. */
int reseed_counter; /*!< The reseed counter.
* This is the number of requests that have
* been made since the last (re)seeding,
* minus one.
* Before the initial seeding, this field
* contains the amount of entropy in bytes
* to use as a nonce for the initial seeding.
*/
int prediction_resistance; /*!< This determines whether prediction
resistance is enabled, that is
whether to systematically reseed before
each random generation. */
size_t entropy_len; /*!< The amount of entropy grabbed on each
seed or reseed operation. */
int reseed_interval; /*!< The reseed interval. */
seed or reseed operation, in bytes. */
int reseed_interval; /*!< The reseed interval.
* This is the maximum number of requests
* that can be made between reseedings. */
mbedtls_aes_context aes_ctx; /*!< The AES context. */
@ -217,43 +228,68 @@ void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx );
* 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.
* The entropy nonce length is:
* - \c 0 if the entropy length is at least 3/2 times the entropy length,
* which guarantees that the security strength is the maximum permitted
* by the key size and entropy length according to NIST SP 800-90A §10.2.1;
* - Half the entropy length otherwise.
* You can override it by calling mbedtls_ctr_drbg_set_nonce_len().
* With the default entropy length, the entropy nonce length is
* #MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN.
*
* \note The _seed_material_ value passed to the derivation
* function in the CTR_DRBG Instantiate Process
* described in NIST SP 800-90A §10.2.1.3.2
* is the concatenation of the string obtained from
* calling \p f_entropy and the \p custom string.
* The origin of the nonce depends on the value of
* the entropy length relative to the security strength.
* - If the entropy length is at least 1.5 times the
* security strength then the nonce is taken from the
* string obtained with \p f_entropy.
* - If the entropy length is less than the security
* strength, then the nonce is taken from \p custom.
* In this case, for compliance with SP 800-90A,
* you must pass a unique value of \p custom at
* each invocation. See SP 800-90A §8.6.7 for more
* details.
* You can provide a nonce and personalization string in addition to the
* entropy source, to make this instantiation as unique as possible.
* See SP 800-90A §8.6.7 for more details about nonces.
*
* The _seed_material_ value passed to the derivation function in
* the CTR_DRBG Instantiate Process described in NIST SP 800-90A §10.2.1.3.2
* is the concatenation of the following strings:
* - A string obtained by calling \p f_entropy function for the entropy
* length.
*/
#if MBEDTLS_CTR_DRBG_ENTROPY_LEN < MBEDTLS_CTR_DRBG_KEYSIZE * 3 / 2
/** \warning When #MBEDTLS_CTR_DRBG_ENTROPY_LEN is less than
* #MBEDTLS_CTR_DRBG_KEYSIZE * 3 / 2, to achieve the
* maximum security strength permitted by CTR_DRBG,
* you must pass a value of \p custom that is a nonce:
* this value must never be repeated in subsequent
* runs of the same application or on a different
* device.
#if MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN == 0
/**
* - If mbedtls_ctr_drbg_set_nonce_len() has been called, a string
* obtained by calling \p f_entropy function for the specified length.
*/
#else
/**
* - A string obtained by calling \p f_entropy function for the entropy nonce
* length. If the entropy nonce length is \c 0, this function does not
* make a second call to \p f_entropy.
*/
#endif
/**
* - The \p custom string.
*
* \note To achieve the nominal security strength permitted
* by CTR_DRBG, the entropy length must be:
* - at least 16 bytes for a 128-bit strength
* (maximum achievable strength when using AES-128);
* - at least 32 bytes for a 256-bit strength
* (maximum achievable strength when using AES-256).
*
* In addition, if you do not pass a nonce in \p custom,
* the sum of the entropy length
* and the entropy nonce length must be:
* - at least 24 bytes for a 128-bit strength
* (maximum achievable strength when using AES-128);
* - at least 48 bytes for a 256-bit strength
* (maximum achievable strength when using AES-256).
*
* \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.
* less than or 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
@ -301,11 +337,6 @@ void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx,
*
* 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
@ -320,11 +351,35 @@ void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx,
*
* \param ctx The CTR_DRBG context.
* \param len The amount of entropy to grab, in bytes.
* This must be at most #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT.
* This must be at most #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT
* and at most the maximum length accepted by the
* entropy function that is set in the context.
*/
void mbedtls_ctr_drbg_set_entropy_len( mbedtls_ctr_drbg_context *ctx,
size_t len );
/**
* \brief This function sets the amount of entropy grabbed
* as a nonce for the initial seeding.
*
* Call this function before calling mbedtls_ctr_drbg_seed() to read
* a nonce from the entropy source during the initial seeding.
*
* \param ctx The CTR_DRBG context.
* \param len The amount of entropy to grab for the nonce, in bytes.
* This must be at most #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT
* and at most the maximum length accepted by the
* entropy function that is set in the context.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG if \p len is
* more than #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT.
* \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED
* if the initial seeding has already taken place.
*/
int mbedtls_ctr_drbg_set_nonce_len( mbedtls_ctr_drbg_context *ctx,
size_t len );
/**
* \brief This function sets the reseed interval.
*

View file

@ -139,7 +139,7 @@ void mbedtls_hmac_drbg_init( mbedtls_hmac_drbg_context *ctx );
* 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 default entropy length is the security strength
* (converted from bits to bytes). You can override
@ -222,14 +222,9 @@ void mbedtls_hmac_drbg_set_prediction_resistance( mbedtls_hmac_drbg_context *ctx
/**
* \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.

View file

@ -56,6 +56,9 @@
void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_ctr_drbg_context ) );
/* Indicate that the entropy nonce length is not set explicitly.
* See mbedtls_ctr_drbg_set_nonce_len(). */
ctx->reseed_counter = -1;
#if defined(MBEDTLS_THREADING_C)
mbedtls_mutex_init( &ctx->mutex );
@ -86,6 +89,32 @@ void mbedtls_ctr_drbg_set_entropy_len( mbedtls_ctr_drbg_context *ctx,
ctx->entropy_len = len;
}
int mbedtls_ctr_drbg_set_nonce_len( mbedtls_ctr_drbg_context *ctx,
size_t len )
{
/* If mbedtls_ctr_drbg_seed() has already been called, it's
* too late. Return the error code that's closest to making sense. */
if( ctx->f_entropy != NULL )
return( MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED );
if( len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT )
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
#if SIZE_MAX > INT_MAX
/* This shouldn't be an issue because
* MBEDTLS_CTR_DRBG_MAX_SEED_INPUT < INT_MAX in any sensible
* configuration, but make sure anyway. */
if( len > INT_MAX )
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
#endif
/* For backward compatibility with Mbed TLS <= 2.19, store the
* entropy nonce length in a field that already exists, but isn't
* used until after the initial seeding. */
/* Due to the capping of len above, the value fits in an int. */
ctx->reseed_counter = (int) len;
return( 0 );
}
void mbedtls_ctr_drbg_set_reseed_interval( mbedtls_ctr_drbg_context *ctx,
int interval )
{
@ -319,7 +348,7 @@ void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx,
#endif /* MBEDTLS_DEPRECATED_REMOVED */
/* CTR_DRBG_Reseed with derivation function (SP 800-90A &sect;10.2.1.4.2)
* mbedtls_ctr_drbg_reseed(ctx, additional, len)
* mbedtls_ctr_drbg_reseed(ctx, additional, len, nonce_len)
* implements
* CTR_DRBG_Reseed(working_state, entropy_input, additional_input)
* -> new_working_state
@ -327,51 +356,57 @@ void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx,
* ctx contains working_state
* additional[:len] = additional_input
* and entropy_input comes from calling ctx->f_entropy
* for (ctx->entropy_len + nonce_len) bytes
* and with output
* ctx contains new_working_state
*/
int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx,
const unsigned char *additional, size_t len )
static int mbedtls_ctr_drbg_reseed_internal( mbedtls_ctr_drbg_context *ctx,
const unsigned char *additional,
size_t len,
size_t nonce_len )
{
unsigned char seed[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT];
size_t seedlen = 0;
int ret;
if( ctx->entropy_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ||
len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len )
if( ctx->entropy_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT )
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
if( nonce_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len )
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
if( len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len - nonce_len )
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
memset( seed, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT );
/*
* Gather entropy_len bytes of entropy to seed state
*/
if( 0 != ctx->f_entropy( ctx->p_entropy, seed,
ctx->entropy_len ) )
/* Gather entropy_len bytes of entropy to seed state. */
if( 0 != ctx->f_entropy( ctx->p_entropy, seed, ctx->entropy_len ) )
{
return( MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED );
}
seedlen += ctx->entropy_len;
/*
* Add additional data
*/
if( additional && len )
/* Gather entropy for a nonce if requested. */
if( nonce_len != 0 )
{
if( 0 != ctx->f_entropy( ctx->p_entropy, seed, nonce_len ) )
{
return( MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED );
}
seedlen += nonce_len;
}
/* Add additional data if provided. */
if( additional != NULL && len != 0 )
{
memcpy( seed + seedlen, additional, len );
seedlen += len;
}
/*
* Reduce to 384 bits
*/
/* Reduce to 384 bits. */
if( ( ret = block_cipher_df( seed, seed, seedlen ) ) != 0 )
goto exit;
/*
* Update state
*/
/* Update state. */
if( ( ret = ctr_drbg_update_internal( ctx, seed ) ) != 0 )
goto exit;
ctx->reseed_counter = 1;
@ -381,15 +416,33 @@ exit:
return( ret );
}
int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx,
const unsigned char *additional, size_t len )
{
return( mbedtls_ctr_drbg_reseed_internal( ctx, additional, len, 0 ) );
}
/* Return a "good" nonce length for CTR_DRBG. The chosen nonce length
* is sufficient to achieve the maximum security strength given the key
* size and entropy length. If there is enough entropy in the initial
* call to the entropy function to serve as both the entropy input and
* the nonce, don't make a second call to get a nonce. */
static size_t good_nonce_len( size_t entropy_len )
{
if( entropy_len >= MBEDTLS_CTR_DRBG_KEYSIZE * 3 / 2 )
return( 0 );
else
return( ( entropy_len + 1 ) / 2 );
}
/* CTR_DRBG_Instantiate with derivation function (SP 800-90A &sect;10.2.1.3.2)
* mbedtls_ctr_drbg_seed_entropy_len(ctx, f_entropy, p_entropy,
* custom, len, entropy_len)
* 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 entropy_len bytes
* where entropy_input comes from f_entropy for ctx->entropy_len bytes
* and with outputs
* ctx = initial_working_state
*/
@ -401,6 +454,7 @@ int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx,
{
int ret;
unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
size_t nonce_len;
memset( key, 0, MBEDTLS_CTR_DRBG_KEYSIZE );
@ -411,18 +465,26 @@ int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx,
if( ctx->entropy_len == 0 )
ctx->entropy_len = MBEDTLS_CTR_DRBG_ENTROPY_LEN;
/* ctx->reseed_counter contains the desired amount of entropy to
* grab for a nonce (see mbedtls_ctr_drbg_set_nonce_len()).
* If it's -1, indicating that the entropy nonce length was not set
* explicitly, use a sufficiently large nonce for security. */
nonce_len = ( ctx->reseed_counter >= 0 ?
(size_t) ctx->reseed_counter :
good_nonce_len( ctx->entropy_len ) );
ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
/*
* Initialize with an empty key
*/
/* 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 )
/* Do the initial seeding. */
if( ( ret = mbedtls_ctr_drbg_reseed_internal( ctx, custom, len,
nonce_len ) ) != 0 )
{
return( ret );
}
@ -693,6 +755,7 @@ int mbedtls_ctr_drbg_self_test( int verbose )
test_offset = 0;
mbedtls_ctr_drbg_set_entropy_len( &ctx, 32 );
mbedtls_ctr_drbg_set_nonce_len( &ctx, 0 );
CHK( mbedtls_ctr_drbg_seed( &ctx,
ctr_drbg_self_test_entropy,
(void *) entropy_source_pr,
@ -717,6 +780,7 @@ int mbedtls_ctr_drbg_self_test( int verbose )
test_offset = 0;
mbedtls_ctr_drbg_set_entropy_len( &ctx, 32 );
mbedtls_ctr_drbg_set_nonce_len( &ctx, 0 );
CHK( mbedtls_ctr_drbg_seed( &ctx,
ctr_drbg_self_test_entropy,
(void *) entropy_source_nopr,

View file

@ -686,12 +686,13 @@ int main( int argc, char *argv[] )
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 );

View file

@ -1070,8 +1070,22 @@ CTR_DRBG CAVS 14.3 (AES-128 use df,True,128,64,0,0) #0
depends_on:MBEDTLS_CTR_DRBG_USE_128_BIT_KEY
ctr_drbg_validate_pr:"d4f1f4ae08bcb3e1":"5d4041942bcf68864a4997d8171f1f9fef55a769b7eaf03fe082029bb32a2b9d8239e865c0a42e14b964b9c09de85a20":"":"":"4155320287eedcf7d484c2c2a1e2eb64b9c9ce77c87202a1ae1616c7a5cfd1c687c7a0bfcc85bda48fdd4629fd330c22d0a76076f88fc7cd04037ee06b7af602"
CTR_DRBG entropy usage
ctr_drbg_entropy_usage:
CTR_DRBG entropy usage (default entropy_nonce_len)
ctr_drbg_entropy_usage:-1
CTR_DRBG entropy usage (entropy_nonce_len=0)
ctr_drbg_entropy_usage:0
CTR_DRBG entropy usage (entropy_nonce_len=7)
ctr_drbg_entropy_usage:7
CTR_DRBG entropy strength: 128 bits
depends_on:MBEDTLS_CTR_DRBG_USE_128_BIT_KEY
ctr_drbg_entropy_strength:128
CTR_DRBG entropy strength: 256 bits
depends_on:!MBEDTLS_CTR_DRBG_USE_128_BIT_KEY
ctr_drbg_entropy_strength:256
CTR_DRBG write/update seed file [#1]
ctr_drbg_seed_file:"data_files/ctr_drbg_seed":0

View file

@ -45,6 +45,7 @@ static void ctr_drbg_validate_internal( int reseed_mode, data_t * nonce,
/* CTR_DRBG_Instantiate(entropy[:entropy->len], nonce, perso, <ignored>)
* where nonce||perso = nonce[nonce->len] */
mbedtls_ctr_drbg_set_entropy_len( &ctx, entropy_chunk_len );
mbedtls_ctr_drbg_set_nonce_len( &ctx, 0 );
TEST_ASSERT( mbedtls_ctr_drbg_seed(
&ctx,
mbedtls_test_entropy_func, entropy->x,
@ -187,17 +188,47 @@ void ctr_drbg_validate_reseed_first( data_t * add_init, data_t * entropy,
}
/* END_CASE */
/* BEGIN_CASE */
void ctr_drbg_entropy_strength( int expected_bit_strength )
{
unsigned char entropy[/*initial entropy*/ MBEDTLS_CTR_DRBG_ENTROPY_LEN +
/*nonce*/ MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN +
/*reseed*/ MBEDTLS_CTR_DRBG_ENTROPY_LEN];
mbedtls_ctr_drbg_context ctx;
size_t last_idx;
size_t byte_strength = expected_bit_strength / 8;
mbedtls_ctr_drbg_init( &ctx );
test_offset_idx = 0;
test_max_idx = sizeof( entropy );
memset( entropy, 0, sizeof( entropy ) );
/* The initial seeding must grab at least byte_strength bytes of entropy
* for the entropy input and byte_strength/2 bytes for a nonce. */
TEST_ASSERT( mbedtls_ctr_drbg_seed( &ctx,
mbedtls_test_entropy_func, entropy,
NULL, 0 ) == 0 );
TEST_ASSERT( test_offset_idx >= ( byte_strength * 3 + 1 ) / 2 );
last_idx = test_offset_idx;
/* A reseed must grab at least byte_strength bytes of entropy. */
TEST_ASSERT( mbedtls_ctr_drbg_reseed( &ctx, NULL, 0 ) == 0 );
TEST_ASSERT( test_offset_idx - last_idx >= byte_strength );
exit:
mbedtls_ctr_drbg_free( &ctx );
}
/* END_CASE */
/* BEGIN_CASE */
void ctr_drbg_entropy_usage( )
void ctr_drbg_entropy_usage( int entropy_nonce_len )
{
unsigned char out[16];
unsigned char add[16];
unsigned char entropy[1024];
mbedtls_ctr_drbg_context ctx;
size_t i, reps = 10;
size_t last_idx;
size_t expected_idx = 0;
mbedtls_ctr_drbg_init( &ctx );
test_offset_idx = 0;
@ -206,21 +237,27 @@ void ctr_drbg_entropy_usage( )
memset( out, 0, sizeof( out ) );
memset( add, 0, sizeof( add ) );
if( entropy_nonce_len >= 0 )
TEST_ASSERT( mbedtls_ctr_drbg_set_nonce_len( &ctx, entropy_nonce_len ) == 0 );
/* Init must use entropy */
last_idx = test_offset_idx;
TEST_ASSERT( mbedtls_ctr_drbg_seed( &ctx, mbedtls_test_entropy_func, entropy, NULL, 0 ) == 0 );
TEST_ASSERT( last_idx < test_offset_idx );
expected_idx += MBEDTLS_CTR_DRBG_ENTROPY_LEN;
if( entropy_nonce_len >= 0 )
expected_idx += entropy_nonce_len;
else
expected_idx += MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN;
TEST_EQUAL( test_offset_idx, expected_idx );
/* By default, PR is off and reseed_interval is large,
* so the next few calls should not use entropy */
last_idx = test_offset_idx;
for( i = 0; i < reps; i++ )
{
TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) - 4 ) == 0 );
TEST_ASSERT( mbedtls_ctr_drbg_random_with_add( &ctx, out, sizeof( out ) - 4,
add, sizeof( add ) ) == 0 );
}
TEST_ASSERT( last_idx == test_offset_idx );
TEST_EQUAL( test_offset_idx, expected_idx );
/* While at it, make sure we didn't write past the requested length */
TEST_ASSERT( out[sizeof( out ) - 4] == 0 );
@ -232,17 +269,17 @@ void ctr_drbg_entropy_usage( )
* so the next call should reseed */
mbedtls_ctr_drbg_set_reseed_interval( &ctx, 2 * reps );
TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
TEST_ASSERT( last_idx < test_offset_idx );
expected_idx += MBEDTLS_CTR_DRBG_ENTROPY_LEN;
TEST_EQUAL( test_offset_idx, expected_idx );
/* The new few calls should not reseed */
last_idx = test_offset_idx;
for( i = 0; i < reps / 2; i++ )
{
TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
TEST_ASSERT( mbedtls_ctr_drbg_random_with_add( &ctx, out, sizeof( out ) ,
add, sizeof( add ) ) == 0 );
}
TEST_ASSERT( last_idx == test_offset_idx );
TEST_EQUAL( test_offset_idx, expected_idx );
/* Call update with too much data (sizeof entropy > MAX(_SEED)_INPUT).
* Make sure it's detected as an error and doesn't cause memory
@ -253,18 +290,19 @@ void ctr_drbg_entropy_usage( )
/* Now enable PR, so the next few calls should all reseed */
mbedtls_ctr_drbg_set_prediction_resistance( &ctx, MBEDTLS_CTR_DRBG_PR_ON );
TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
TEST_ASSERT( last_idx < test_offset_idx );
expected_idx += MBEDTLS_CTR_DRBG_ENTROPY_LEN;
TEST_EQUAL( test_offset_idx, expected_idx );
/* Finally, check setting entropy_len */
mbedtls_ctr_drbg_set_entropy_len( &ctx, 42 );
last_idx = test_offset_idx;
TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
TEST_ASSERT( test_offset_idx - last_idx == 42 );
expected_idx += 42;
TEST_EQUAL( test_offset_idx, expected_idx );
mbedtls_ctr_drbg_set_entropy_len( &ctx, 13 );
last_idx = test_offset_idx;
TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
TEST_ASSERT( test_offset_idx - last_idx == 13 );
expected_idx += 13;
TEST_EQUAL( test_offset_idx, expected_idx );
exit:
mbedtls_ctr_drbg_free( &ctx );

View file

@ -37,7 +37,9 @@ void hmac_drbg_entropy_usage( int md_alg )
const mbedtls_md_info_t *md_info;
mbedtls_hmac_drbg_context ctx;
entropy_ctx entropy;
size_t last_len, i, reps = 10;
size_t i, reps = 10;
size_t default_entropy_len;
size_t expected_consumed_entropy = 0;
mbedtls_hmac_drbg_init( &ctx );
memset( buf, 0, sizeof( buf ) );
@ -48,23 +50,29 @@ void hmac_drbg_entropy_usage( int md_alg )
md_info = mbedtls_md_info_from_type( md_alg );
TEST_ASSERT( md_info != NULL );
if( mbedtls_md_get_size( md_info ) <= 20 )
default_entropy_len = 16;
else if( mbedtls_md_get_size( md_info ) <= 28 )
default_entropy_len = 24;
else
default_entropy_len = 32;
/* Init must use entropy */
last_len = entropy.len;
TEST_ASSERT( mbedtls_hmac_drbg_seed( &ctx, md_info, mbedtls_test_entropy_func, &entropy,
NULL, 0 ) == 0 );
TEST_ASSERT( entropy.len < last_len );
/* default_entropy_len of entropy, plus half as much for the nonce */
expected_consumed_entropy += default_entropy_len * 3 / 2;
TEST_EQUAL( sizeof( buf ) - entropy.len, expected_consumed_entropy );
/* By default, PR is off and reseed_interval is large,
* so the next few calls should not use entropy */
last_len = entropy.len;
for( i = 0; i < reps; i++ )
{
TEST_ASSERT( mbedtls_hmac_drbg_random( &ctx, out, sizeof( out ) - 4 ) == 0 );
TEST_ASSERT( mbedtls_hmac_drbg_random_with_add( &ctx, out, sizeof( out ) - 4,
buf, 16 ) == 0 );
}
TEST_ASSERT( entropy.len == last_len );
TEST_EQUAL( sizeof( buf ) - entropy.len, expected_consumed_entropy );
/* While at it, make sure we didn't write past the requested length */
TEST_ASSERT( out[sizeof( out ) - 4] == 0 );
@ -76,33 +84,34 @@ void hmac_drbg_entropy_usage( int md_alg )
* so the next call should reseed */
mbedtls_hmac_drbg_set_reseed_interval( &ctx, 2 * reps );
TEST_ASSERT( mbedtls_hmac_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
TEST_ASSERT( entropy.len < last_len );
expected_consumed_entropy += default_entropy_len;
TEST_EQUAL( sizeof( buf ) - entropy.len, expected_consumed_entropy );
/* The new few calls should not reseed */
last_len = entropy.len;
for( i = 0; i < reps / 2; i++ )
{
TEST_ASSERT( mbedtls_hmac_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
TEST_ASSERT( mbedtls_hmac_drbg_random_with_add( &ctx, out, sizeof( out ) ,
buf, 16 ) == 0 );
}
TEST_ASSERT( entropy.len == last_len );
TEST_EQUAL( sizeof( buf ) - entropy.len, expected_consumed_entropy );
/* Now enable PR, so the next few calls should all reseed */
mbedtls_hmac_drbg_set_prediction_resistance( &ctx, MBEDTLS_HMAC_DRBG_PR_ON );
TEST_ASSERT( mbedtls_hmac_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
TEST_ASSERT( entropy.len < last_len );
expected_consumed_entropy += default_entropy_len;
TEST_EQUAL( sizeof( buf ) - entropy.len, expected_consumed_entropy );
/* Finally, check setting entropy_len */
mbedtls_hmac_drbg_set_entropy_len( &ctx, 42 );
last_len = entropy.len;
TEST_ASSERT( mbedtls_hmac_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
TEST_ASSERT( (int) last_len - entropy.len == 42 );
expected_consumed_entropy += 42;
TEST_EQUAL( sizeof( buf ) - entropy.len, expected_consumed_entropy );
mbedtls_hmac_drbg_set_entropy_len( &ctx, 13 );
last_len = entropy.len;
TEST_ASSERT( mbedtls_hmac_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
TEST_ASSERT( (int) last_len - entropy.len == 13 );
expected_consumed_entropy += 13;
TEST_EQUAL( sizeof( buf ) - entropy.len, expected_consumed_entropy );
exit:
mbedtls_hmac_drbg_free( &ctx );

View file

@ -34,15 +34,25 @@ fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:0:0:0:0:PSA_ERROR_INSUFFICIENT_EN
Fake entropy: less than the block size
fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:-1:-1:-1:PSA_ERROR_INSUFFICIENT_ENTROPY
Fake entropy: not enough for a nonce
depends_on:ENTROPY_NONCE_LEN != 0
fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:ENTROPY_NONCE_LEN - 1:-1:-1:-1:PSA_ERROR_INSUFFICIENT_ENTROPY
Fake entropy: one block eventually
depends_on:ENTROPY_NONCE_LEN == 0
fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:0:0:0:MBEDTLS_ENTROPY_BLOCK_SIZE:PSA_SUCCESS
Fake entropy: one block in two steps
depends_on:ENTROPY_NONCE_LEN == 0
fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:1:-1:-1:PSA_SUCCESS
Fake entropy: more than one block in two steps
depends_on:ENTROPY_NONCE_LEN == 0
fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:-1:-1:PSA_SUCCESS
Fake entropy: two blocks eventually
fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:0:MBEDTLS_ENTROPY_BLOCK_SIZE:0:MBEDTLS_ENTROPY_BLOCK_SIZE:PSA_SUCCESS
NV seed only: less than minimum
entropy_from_nv_seed:MBEDTLS_ENTROPY_MIN_PLATFORM - 1:PSA_ERROR_INSUFFICIENT_ENTROPY

View file

@ -11,6 +11,12 @@
#define ENTROPY_MIN_NV_SEED_SIZE \
MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_BLOCK_SIZE)
/* PSA crypto uses the CTR_DRBG module. In some configurations, it needs
* to read from the entropy source twice: once for the initial entropy
* and once for a nonce. */
#include "mbedtls/ctr_drbg.h"
#define ENTROPY_NONCE_LEN MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN
typedef struct
{
size_t threshold; /* Minimum bytes to make mbedtls_entropy_func happy */