Skip to content

Commit c06f3b5

Browse files
CTR_DRBG: during initial seeding, grab entropy for a nonce
CTR_DRBG always grabbed MBEDTLS_CTR_DRBG_ENTROPY_LEN during the initial seeding. In some configurations, in particular when using SHA-256 for entropy, this was a bottleneck on the security strength: with only 32 bytes of entropy, there was not enough entropy for both the entropy input and a nonce per NIST specifications. This required a workaround where the user had to pass a nonce through the `custom` parameter of mbedtls_ctr_drbg_seed() to achieve the desired security strength in some cases. To make things simple, always make a second call to the f_entropy function during the initial seeding, to grab a nonce. Update the code, the documentation and the tests accordingly. Modify the internal function mbedtls_ctr_drbg_set_entropy_len() to grab the desired amount of entropy when running NIST test vectors. As this function was not used from any other module (it was only exposed for the sake of the test suite), this does not break the ABI as far as library users are concerned.
1 parent 0033fd3 commit c06f3b5

File tree

3 files changed

+92
-92
lines changed

3 files changed

+92
-92
lines changed

include/mbedtls/ctr_drbg.h

Lines changed: 31 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -10,32 +10,19 @@
1010
* Bit Generators</em>.
1111
*
1212
* The Mbed TLS implementation of CTR_DRBG uses AES-256 (default) or AES-128
13-
* (if \c MBEDTLS_CTR_DRBG_USE_128_BIT_KEY is enabled at compile time)
14-
* as the underlying block cipher, with a derivation function.
15-
* The initial seeding grabs #MBEDTLS_CTR_DRBG_ENTROPY_LEN bytes of entropy.
16-
* See the documentation of mbedtls_ctr_drbg_seed() for more details.
17-
*
18-
* Based on NIST SP 800-90A §10.2.1 table 3 and NIST SP 800-57 part 1 table 2,
19-
* here are the security strengths achieved in typical configuration:
20-
* - 256 bits under the default configuration of the library, with AES-256
21-
* and with #MBEDTLS_CTR_DRBG_ENTROPY_LEN set to 48 or more.
22-
* - 256 bits if AES-256 is used, #MBEDTLS_CTR_DRBG_ENTROPY_LEN is set
23-
* to 32 or more, and the DRBG is initialized with an explicit
24-
* nonce in the \c custom parameter to mbedtls_ctr_drbg_seed().
25-
* - 128 bits if AES-256 is used but #MBEDTLS_CTR_DRBG_ENTROPY_LEN is
26-
* between 24 and 47 and the DRBG is not initialized with an explicit
27-
* nonce (see mbedtls_ctr_drbg_seed()).
28-
* - 128 bits if AES-128 is used (\c MBEDTLS_CTR_DRBG_USE_128_BIT_KEY set)
29-
* and #MBEDTLS_CTR_DRBG_ENTROPY_LEN is set to 24 or more (which is
30-
* always the case unless it is explicitly set to a different value
31-
* in config.h).
13+
* (if #MBEDTLS_CTR_DRBG_USE_128_BIT_KEY is enabled at compile time)
14+
* as the underlying block cipher, with a derivation function. The security
15+
* strength is the smaller of the AES key size and the entropy length.
3216
*
3317
* Note that the value of #MBEDTLS_CTR_DRBG_ENTROPY_LEN defaults to:
34-
* - \c 48 if the module \c MBEDTLS_SHA512_C is enabled and the symbol
35-
* \c MBEDTLS_ENTROPY_FORCE_SHA256 is disabled at compile time.
18+
* - \c 48 bytes if the module #MBEDTLS_SHA512_C is enabled and the symbol
19+
* #MBEDTLS_ENTROPY_FORCE_SHA256 is not enabled at compile time.
3620
* This is the default configuration of the library.
37-
* - \c 32 if the module \c MBEDTLS_SHA512_C is disabled at compile time.
38-
* - \c 32 if \c MBEDTLS_ENTROPY_FORCE_SHA256 is enabled at compile time.
21+
* - \c 32 bytes if the module #MBEDTLS_SHA512_C is disabled at compile time.
22+
* - \c 32 bytes if #MBEDTLS_ENTROPY_FORCE_SHA256 is enabled at compile time.
23+
*
24+
* This is always sufficient to reach the maximum security strength that can
25+
* be achieved given the AES key size.
3926
*/
4027
/*
4128
* Copyright (C) 2006-2019, Arm Limited (or its affiliates), All Rights Reserved
@@ -123,15 +110,16 @@
123110
* (the SHA512 module is disabled or
124111
* \c MBEDTLS_ENTROPY_FORCE_SHA256 is enabled).
125112
*/
126-
#if !defined(MBEDTLS_CTR_DRBG_USE_128_BIT_KEY)
127-
/** \warning To achieve a 256-bit security strength, you must pass a nonce
128-
* to mbedtls_ctr_drbg_seed().
129-
*/
130-
#endif /* !defined(MBEDTLS_CTR_DRBG_USE_128_BIT_KEY) */
131113
#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 32
132114
#endif /* defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_ENTROPY_FORCE_SHA256) */
133115
#endif /* !defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) */
134116

117+
/** The length of the nonce for the initial seeding.
118+
*
119+
* This implementation always reads a nonce from the entropy source.
120+
*/
121+
#define MBEDTLS_CTR_DRBG_NONCE_LEN (MBEDTLS_CTR_DRBG_ENTROPY_LEN / 2)
122+
135123
#if !defined(MBEDTLS_CTR_DRBG_RESEED_INTERVAL)
136124
#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 10000
137125
/**< The interval before reseed is performed by default. */
@@ -214,41 +202,23 @@ void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx );
214202
* with mbedtls_entropy_init() (which registers the platform's default
215203
* entropy sources).
216204
*
217-
* \p f_entropy is always called with a buffer size equal to the entropy
205+
* \p f_entropy is always called with a buffer size less or equal to the entropy
218206
* length. The entropy length is initially #MBEDTLS_CTR_DRBG_ENTROPY_LEN
219207
* and can be changed by calling mbedtls_ctr_drbg_set_entropy_len().
220208
*
221209
* You can provide a personalization string in addition to the
222210
* entropy source, to make this instantiation as unique as possible.
223211
*
224-
* \note The _seed_material_ value passed to the derivation
225-
* function in the CTR_DRBG Instantiate Process
226-
* described in NIST SP 800-90A §10.2.1.3.2
227-
* is the concatenation of the string obtained from
228-
* calling \p f_entropy and the \p custom string.
229-
* The origin of the nonce depends on the value of
230-
* the entropy length relative to the security strength.
231-
* - If the entropy length is at least 1.5 times the
232-
* security strength then the nonce is taken from the
233-
* string obtained with \p f_entropy.
234-
* - If the entropy length is less than the security
235-
* strength, then the nonce is taken from \p custom.
236-
* In this case, for compliance with SP 800-90A,
237-
* you must pass a unique value of \p custom at
238-
* each invocation. See SP 800-90A §8.6.7 for more
239-
* details.
240-
*/
241-
#if MBEDTLS_CTR_DRBG_ENTROPY_LEN < MBEDTLS_CTR_DRBG_KEYSIZE * 3 / 2
242-
/** \warning When #MBEDTLS_CTR_DRBG_ENTROPY_LEN is less than
243-
* #MBEDTLS_CTR_DRBG_KEYSIZE * 3 / 2, to achieve the
244-
* maximum security strength permitted by CTR_DRBG,
245-
* you must pass a value of \p custom that is a nonce:
246-
* this value must never be repeated in subsequent
247-
* runs of the same application or on a different
248-
* device.
249-
*/
250-
#endif
251-
/**
212+
* The _seed_material_ value passed to the derivation
213+
* function in the CTR_DRBG Instantiate Process
214+
* described in NIST SP 800-90A §10.2.1.3.2
215+
* is the concatenation of:
216+
* - the entropy input, obtained by calling \p f_entropy for
217+
* #MBEDTLS_CTR_DRBG_ENTROPY_LEN bytes;
218+
* - the nonce, obtained by calling \p f_entropy for
219+
* #MBEDTLS_CTR_DRBG_NONCE_LEN bytes;
220+
* - the \p custom string.
221+
*
252222
* \param ctx The CTR_DRBG context to seed.
253223
* \param f_entropy The entropy callback, taking as arguments the
254224
* \p p_entropy context, the buffer to fill, and the
@@ -261,6 +231,7 @@ void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx );
261231
* This must be at most
262232
* #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT
263233
* - #MBEDTLS_CTR_DRBG_ENTROPY_LEN.
234+
* - #MBEDTLS_CTR_DRBG_NONCE_LEN.
264235
*
265236
* \return \c 0 on success.
266237
* \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED on failure.
@@ -300,22 +271,8 @@ void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx,
300271
*
301272
* The default value is #MBEDTLS_CTR_DRBG_ENTROPY_LEN.
302273
*
303-
* \note The security strength of CTR_DRBG is bounded by the
304-
* entropy length. Thus:
305-
* - When using AES-256
306-
* (\c MBEDTLS_CTR_DRBG_USE_128_BIT_KEY is disabled,
307-
* which is the default),
308-
* \p len must be at least 32 (in bytes)
309-
* to achieve a 256-bit strength.
310-
* - When using AES-128
311-
* (\c MBEDTLS_CTR_DRBG_USE_128_BIT_KEY is enabled)
312-
* \p len must be at least 16 (in bytes)
313-
* to achieve a 128-bit strength.
314-
*
315-
* \note The initial seeding of the CTR_DRBG instance always
316-
* grabs #MBEDTLS_CTR_DRBG_ENTROPY_LEN bytes. See
317-
* the documentation of mbedtls_ctr_drbg_seed()
318-
* for more information.
274+
* This function has no effect on the initial seeding,
275+
* even if you call it before mbedtls_ctr_drbg_seed().
319276
*
320277
* \param ctx The CTR_DRBG context.
321278
* \param len The amount of entropy to grab, in bytes.
@@ -500,7 +457,7 @@ int mbedtls_ctr_drbg_self_test( int verbose );
500457
/* Internal functions (do not call directly) */
501458
int mbedtls_ctr_drbg_seed_entropy_len( mbedtls_ctr_drbg_context *,
502459
int (*)(void *, unsigned char *, size_t), void *,
503-
const unsigned char *, size_t, size_t );
460+
const unsigned char *, size_t, size_t, size_t );
504461

505462
#ifdef __cplusplus
506463
}

library/ctr_drbg.c

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -330,30 +330,43 @@ void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx,
330330
* and with output
331331
* ctx contains new_working_state
332332
*/
333-
int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx,
334-
const unsigned char *additional, size_t len )
333+
static int mbedtls_ctr_drbg_reseed_core(
334+
mbedtls_ctr_drbg_context *ctx,
335+
const unsigned char *additional, size_t len,
336+
size_t nonce_length )
335337
{
336338
unsigned char seed[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT];
337339
size_t seedlen = 0;
338340
int ret;
339341

340-
if( ctx->entropy_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ||
341-
len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len )
342+
if( ctx->entropy_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - nonce_length )
343+
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
344+
if( len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - nonce_length - ctx->entropy_len )
342345
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
343346

344347
memset( seed, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT );
345348

346349
/*
347350
* Gather entropy_len bytes of entropy to seed state
348351
*/
349-
if( 0 != ctx->f_entropy( ctx->p_entropy, seed,
350-
ctx->entropy_len ) )
352+
if( 0 != ctx->f_entropy( ctx->p_entropy, seed, ctx->entropy_len ) )
351353
{
352354
return( MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED );
353355
}
354-
355356
seedlen += ctx->entropy_len;
356357

358+
/*
359+
* Gather nonce_len bytes of nonce if requested
360+
*/
361+
if( nonce_length > 0 )
362+
{
363+
if( 0 != ctx->f_entropy( ctx->p_entropy, seed, nonce_length ) )
364+
{
365+
return( MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED );
366+
}
367+
seedlen += nonce_length;
368+
}
369+
357370
/*
358371
* Add additional data
359372
*/
@@ -381,6 +394,24 @@ int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx,
381394
return( ret );
382395
}
383396

397+
/* CTR_DRBG_Reseed with derivation function (SP 800-90A &sect;10.2.1.4.2)
398+
* mbedtls_ctr_drbg_reseed(ctx, additional, len)
399+
* implements
400+
* CTR_DRBG_Reseed(working_state, entropy_input, additional_input)
401+
* -> new_working_state
402+
* with inputs
403+
* ctx contains working_state
404+
* additional[:len] = additional_input
405+
* and entropy_input comes from calling ctx->f_entropy
406+
* and with output
407+
* ctx contains new_working_state
408+
*/
409+
int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx,
410+
const unsigned char *additional, size_t len )
411+
{
412+
return( mbedtls_ctr_drbg_reseed_core( ctx, additional, len, 0 ) );
413+
}
414+
384415
/*
385416
* Non-public function wrapped by mbedtls_ctr_drbg_seed(). Necessary to allow
386417
* NIST tests to succeed (which require known length fixed entropy)
@@ -403,7 +434,7 @@ int mbedtls_ctr_drbg_seed_entropy_len(
403434
void *p_entropy,
404435
const unsigned char *custom,
405436
size_t len,
406-
size_t entropy_len )
437+
size_t entropy_len, size_t nonce_length )
407438
{
408439
int ret;
409440
unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
@@ -427,7 +458,8 @@ int mbedtls_ctr_drbg_seed_entropy_len(
427458
return( ret );
428459
}
429460

430-
if( ( ret = mbedtls_ctr_drbg_reseed( ctx, custom, len ) ) != 0 )
461+
if( ( ret = mbedtls_ctr_drbg_reseed_core( ctx, custom, len,
462+
nonce_length ) ) != 0 )
431463
{
432464
return( ret );
433465
}
@@ -442,7 +474,8 @@ int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx,
442474
{
443475
return( mbedtls_ctr_drbg_seed_entropy_len( ctx, f_entropy, p_entropy,
444476
custom, len,
445-
MBEDTLS_CTR_DRBG_ENTROPY_LEN ) );
477+
MBEDTLS_CTR_DRBG_ENTROPY_LEN,
478+
MBEDTLS_CTR_DRBG_NONCE_LEN ) );
446479
}
447480

448481
/* CTR_DRBG_Generate with derivation function (SP 800-90A &sect;10.2.1.5.2)
@@ -708,8 +741,11 @@ int mbedtls_ctr_drbg_self_test( int verbose )
708741
mbedtls_printf( " CTR_DRBG (PR = TRUE) : " );
709742

710743
test_offset = 0;
711-
CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy,
712-
(void *) entropy_source_pr, nonce_pers_pr, 16, 32 ) );
744+
CHK( mbedtls_ctr_drbg_seed_entropy_len(
745+
&ctx,
746+
ctr_drbg_self_test_entropy, (void *) entropy_source_pr,
747+
nonce_pers_pr, 16,
748+
32, 0 ) );
713749
mbedtls_ctr_drbg_set_prediction_resistance( &ctx, MBEDTLS_CTR_DRBG_PR_ON );
714750
CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) );
715751
CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) );
@@ -729,8 +765,11 @@ int mbedtls_ctr_drbg_self_test( int verbose )
729765
mbedtls_ctr_drbg_init( &ctx );
730766

731767
test_offset = 0;
732-
CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy,
733-
(void *) entropy_source_nopr, nonce_pers_nopr, 16, 32 ) );
768+
CHK( mbedtls_ctr_drbg_seed_entropy_len(
769+
&ctx,
770+
ctr_drbg_self_test_entropy, (void *) entropy_source_nopr,
771+
nonce_pers_nopr, 16,
772+
32, 0 ) );
734773
CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) );
735774
CHK( mbedtls_ctr_drbg_reseed( &ctx, NULL, 0 ) );
736775
CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) );

tests/suites/test_suite_ctr_drbg.function

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ static int mbedtls_test_entropy_func( void *data, unsigned char *buf, size_t len
2424
return( 0 );
2525
}
2626

27-
static void ctr_drbg_validate_internal( int reseed_mode, data_t * nonce,
27+
static void ctr_drbg_validate_internal( int reseed_mode, data_t * custom,
2828
int entropy_len_arg, data_t * entropy,
2929
data_t * reseed,
3030
data_t * add1, data_t * add2,
@@ -43,12 +43,16 @@ static void ctr_drbg_validate_internal( int reseed_mode, data_t * nonce,
4343
test_max_idx = entropy->len;
4444

4545
/* CTR_DRBG_Instantiate(entropy[:entropy->len], nonce, perso, <ignored>)
46-
* where nonce||perso = nonce[nonce->len] */
46+
* where nonce||perso = custom[nonce->len].
47+
* The library interface doesn't allow specifying a nonce, so we test
48+
* with an empty nonce, and pass some personalization data instead.
49+
* Since under the hood all that matters is the concatenation of the
50+
* nonce with the personalization data, this is equivalent. */
4751
TEST_ASSERT( mbedtls_ctr_drbg_seed_entropy_len(
4852
&ctx,
4953
mbedtls_test_entropy_func, entropy->x,
50-
nonce->x, nonce->len,
51-
entropy_chunk_len ) == 0 );
54+
custom->x, custom->len,
55+
entropy_chunk_len, 0 ) == 0 );
5256
if( reseed_mode == RESEED_ALWAYS )
5357
mbedtls_ctr_drbg_set_prediction_resistance(
5458
&ctx,

0 commit comments

Comments
 (0)