Skip to content

Commit 9be5098

Browse files
CTR_DRBG: add the possibility of grabbing entropy for a nonce
Add a new function mbedtls_ctr_drbg_set_nonce_len() which configures the DRBG instance to call f_entropy a second time during the initial seeding to grab a nonce. The default nonce length is 0, so there is no behavior change unless the user calls the new function.
1 parent dbd3f7c commit 9be5098

File tree

2 files changed

+125
-40
lines changed

2 files changed

+125
-40
lines changed

include/mbedtls/ctr_drbg.h

Lines changed: 68 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,19 @@
2222
* - 256 bits if AES-256 is used, #MBEDTLS_CTR_DRBG_ENTROPY_LEN is set
2323
* to 32 or more, and the DRBG is initialized with an explicit
2424
* nonce in the \c custom parameter to mbedtls_ctr_drbg_seed().
25+
* - 256 bits if AES-256 is used, #MBEDTLS_CTR_DRBG_ENTROPY_LEN is set
26+
* to 32 or more, and mbedtls_ctr_drbg_set_nonce_len() is called to set
27+
* an entropy nonce length of 16 bytes or more.
2528
* - 128 bits if AES-256 is used but #MBEDTLS_CTR_DRBG_ENTROPY_LEN is
2629
* between 24 and 47 and the DRBG is not initialized with an explicit
2730
* nonce (see mbedtls_ctr_drbg_seed()).
2831
* - 128 bits if AES-128 is used (\c MBEDTLS_CTR_DRBG_USE_128_BIT_KEY enabled)
2932
* and #MBEDTLS_CTR_DRBG_ENTROPY_LEN is set to 24 or more (which is
3033
* always the case unless it is explicitly set to a different value
3134
* in config.h).
35+
* - 128 bits if AES-128 is used (\c MBEDTLS_CTR_DRBG_USE_128_BIT_KEY enabled)
36+
* to 16 or more, and mbedtls_ctr_drbg_set_nonce_len() is called to set
37+
* an entropy nonce length of 8 bytes or more.
3238
*
3339
* Note that the value of #MBEDTLS_CTR_DRBG_ENTROPY_LEN defaults to:
3440
* - \c 48 if the module \c MBEDTLS_SHA512_C is enabled and the symbol
@@ -172,7 +178,11 @@ typedef struct mbedtls_ctr_drbg_context
172178
int reseed_counter; /*!< The reseed counter.
173179
* This is the number of requests that have
174180
* been made since the last (re)seeding,
175-
* minus one. */
181+
* minus one.
182+
* Before the initial seeding, this field
183+
* contains the amount of entropy in bytes
184+
* to use as a nonce for the initial seeding.
185+
*/
176186
int prediction_resistance; /*!< This determines whether prediction
177187
resistance is enabled, that is
178188
whether to systematically reseed before
@@ -222,43 +232,45 @@ void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx );
222232
* The entropy length is #MBEDTLS_CTR_DRBG_ENTROPY_LEN by default.
223233
* You can override it by calling mbedtls_ctr_drbg_set_entropy_len().
224234
*
225-
* You can provide a personalization string in addition to the
235+
* You can provide a nonce and personalization string in addition to the
226236
* entropy source, to make this instantiation as unique as possible.
237+
* See SP 800-90A §8.6.7 for more details about nonces.
238+
*
239+
* The _seed_material_ value passed to the derivation function in
240+
* the CTR_DRBG Instantiate Process described in NIST SP 800-90A §10.2.1.3.2
241+
* is the concatenation of the following strings:
242+
* - A string obtained by calling \p f_entropy function for the entropy
243+
* length.
244+
* - A string obtained by calling \p f_entropy function for the nonce
245+
* length set with mbedtls_ctr_drbg_set_nonce_len(). If the entropy
246+
* nonce length is \c 0, this function does not make a second call
247+
* to \p f_entropy.
248+
* - The \p custom string.
249+
*
250+
* \note To achieve the nominal security strength permitted
251+
* by CTR_DRBG, the entropy length must be:
252+
* - at least 16 bytes for a 128-bit strength
253+
* (maximum achievable strength when using AES-128);
254+
* - at least 32 bytes for a 256-bit strength
255+
* (maximum achievable strength when using AES-256).
256+
*
257+
* In addition, if you do not pass a nonce in \p custom,
258+
* the sum of the entropy length
259+
* (#MBEDTLS_CTR_DRBG_ENTROPY_LEN unless overridden with
260+
* mbedtls_ctr_drbg_set_entropy_len())
261+
* and the entropy nonce length (\c 0 unless overridden
262+
* with mbedtls_ctr_drbg_set_nonce_len()) must be:
263+
* - at least 24 bytes for a 128-bit strength
264+
* (maximum achievable strength when using AES-128);
265+
* - at least 48 bytes for a 256-bit strength
266+
* (maximum achievable strength when using AES-256).
227267
*
228-
* \note The _seed_material_ value passed to the derivation
229-
* function in the CTR_DRBG Instantiate Process
230-
* described in NIST SP 800-90A §10.2.1.3.2
231-
* is the concatenation of the string obtained from
232-
* calling \p f_entropy and the \p custom string.
233-
* The origin of the nonce depends on the value of
234-
* the entropy length relative to the security strength.
235-
* - If the entropy length is at least 1.5 times the
236-
* security strength then the nonce is taken from the
237-
* string obtained with \p f_entropy.
238-
* - If the entropy length is less than the security
239-
* strength, then the nonce is taken from \p custom.
240-
* In this case, for compliance with SP 800-90A,
241-
* you must pass a unique value of \p custom at
242-
* each invocation. See SP 800-90A §8.6.7 for more
243-
* details.
244-
*/
245-
#if MBEDTLS_CTR_DRBG_ENTROPY_LEN < MBEDTLS_CTR_DRBG_KEYSIZE * 3 / 2
246-
/** \warning When #MBEDTLS_CTR_DRBG_ENTROPY_LEN is less than
247-
* #MBEDTLS_CTR_DRBG_KEYSIZE * 3 / 2, to achieve the
248-
* maximum security strength permitted by CTR_DRBG,
249-
* you must pass a value of \p custom that is a nonce:
250-
* this value must never be repeated in subsequent
251-
* runs of the same application or on a different
252-
* device.
253-
*/
254-
#endif
255-
/**
256268
* \param ctx The CTR_DRBG context to seed.
257269
* \param f_entropy The entropy callback, taking as arguments the
258270
* \p p_entropy context, the buffer to fill, and the
259271
* length of the buffer.
260272
* \p f_entropy is always called with a buffer size
261-
* equal to the entropy length.
273+
* less than or equal to the entropy length.
262274
* \param p_entropy The entropy context to pass to \p f_entropy.
263275
* \param custom The personalization string.
264276
* This can be \c NULL, in which case the personalization
@@ -320,11 +332,35 @@ void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx,
320332
*
321333
* \param ctx The CTR_DRBG context.
322334
* \param len The amount of entropy to grab, in bytes.
323-
* This must be at most #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT.
335+
* This must be at most #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT
336+
* and at most the maximum length accepted by the
337+
* entropy function that is set in the context.
324338
*/
325339
void mbedtls_ctr_drbg_set_entropy_len( mbedtls_ctr_drbg_context *ctx,
326340
size_t len );
327341

342+
/**
343+
* \brief This function sets the amount of entropy grabbed
344+
* as a nonce for the initial seeding.
345+
*
346+
* Call this function before calling mbedtls_ctr_drbg_seed() to read
347+
* a nonce from the entropy source during the initial seeding.
348+
*
349+
* \param ctx The CTR_DRBG context.
350+
* \param len The amount of entropy to grab for the nonce, in bytes.
351+
* This must be at most #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT
352+
* and at most the maximum length accepted by the
353+
* entropy function that is set in the context.
354+
*
355+
* \return \c 0 on success.
356+
* \return #MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG if \p len is
357+
* more than #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT.
358+
* \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED
359+
* if the initial seeding has already taken place.
360+
*/
361+
int mbedtls_ctr_drbg_set_nonce_len( mbedtls_ctr_drbg_context *ctx,
362+
size_t len );
363+
328364
/**
329365
* \brief This function sets the reseed interval.
330366
*

library/ctr_drbg.c

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,32 @@ void mbedtls_ctr_drbg_set_entropy_len( mbedtls_ctr_drbg_context *ctx,
8686
ctx->entropy_len = len;
8787
}
8888

89+
int mbedtls_ctr_drbg_set_nonce_len( mbedtls_ctr_drbg_context *ctx,
90+
size_t len )
91+
{
92+
/* If mbedtls_ctr_drbg_seed() has already been called, it's
93+
* too late. Return the error code that's closest to making sense. */
94+
if( ctx->f_entropy != NULL )
95+
return( MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED );
96+
97+
if( len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT )
98+
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
99+
#if SIZE_MAX > INT_MAX
100+
/* This shouldn't be an issue because
101+
* MBEDTLS_CTR_DRBG_MAX_SEED_INPUT < INT_MAX in any sensible
102+
* configuration, but make sure anyway. */
103+
if( len > INT_MAX )
104+
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
105+
#endif
106+
107+
/* For backward compatibility with Mbed TLS <= 2.19, store the
108+
* entropy nonce length in a field that already exists, but isn't
109+
* used until after the initial seeding. */
110+
/* Due to the capping of len above, the value fits in an int. */
111+
ctx->reseed_counter = (int) len;
112+
return( 0 );
113+
}
114+
89115
void mbedtls_ctr_drbg_set_reseed_interval( mbedtls_ctr_drbg_context *ctx,
90116
int interval )
91117
{
@@ -319,27 +345,32 @@ void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx,
319345
#endif /* MBEDTLS_DEPRECATED_REMOVED */
320346

321347
/* CTR_DRBG_Reseed with derivation function (SP 800-90A &sect;10.2.1.4.2)
322-
* mbedtls_ctr_drbg_reseed(ctx, additional, len)
348+
* mbedtls_ctr_drbg_reseed(ctx, additional, len, nonce_len)
323349
* implements
324350
* CTR_DRBG_Reseed(working_state, entropy_input, additional_input)
325351
* -> new_working_state
326352
* with inputs
327353
* ctx contains working_state
328354
* additional[:len] = additional_input
329355
* and entropy_input comes from calling ctx->f_entropy
356+
* for (ctx->entropy_len + nonce_len) bytes
330357
* and with output
331358
* ctx contains new_working_state
332359
*/
333-
int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx,
334-
const unsigned char *additional, size_t len )
360+
int mbedtls_ctr_drbg_reseed_internal( mbedtls_ctr_drbg_context *ctx,
361+
const unsigned char *additional,
362+
size_t len,
363+
size_t nonce_len )
335364
{
336365
unsigned char seed[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT];
337366
size_t seedlen = 0;
338367
int ret;
339368

340369
if( ctx->entropy_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT )
341370
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
342-
if( len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len )
371+
if( nonce_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len )
372+
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
373+
if( len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len - nonce_len )
343374
return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
344375

345376
memset( seed, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT );
@@ -351,6 +382,16 @@ int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx,
351382
}
352383
seedlen += ctx->entropy_len;
353384

385+
/* Gather entropy for a nonce if requested. */
386+
if( nonce_len != 0 )
387+
{
388+
if( 0 != ctx->f_entropy( ctx->p_entropy, seed, nonce_len ) )
389+
{
390+
return( MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED );
391+
}
392+
seedlen += nonce_len;
393+
}
394+
354395
/* Add additional data if provided. */
355396
if( additional != NULL && len != 0 )
356397
{
@@ -372,6 +413,12 @@ int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx,
372413
return( ret );
373414
}
374415

416+
int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx,
417+
const unsigned char *additional, size_t len )
418+
{
419+
return( mbedtls_ctr_drbg_reseed_internal( ctx, additional, len, 0 ) );
420+
}
421+
375422
/* CTR_DRBG_Instantiate with derivation function (SP 800-90A &sect;10.2.1.3.2)
376423
* mbedtls_ctr_drbg_seed(ctx, f_entropy, p_entropy, custom, len)
377424
* implements
@@ -403,16 +450,18 @@ int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx,
403450
ctx->entropy_len = MBEDTLS_CTR_DRBG_ENTROPY_LEN;
404451
ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
405452

406-
/*
407-
* Initialize with an empty key
408-
*/
453+
/* Initialize with an empty key. */
409454
if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, key,
410455
MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
411456
{
412457
return( ret );
413458
}
414459

415-
if( ( ret = mbedtls_ctr_drbg_reseed( ctx, custom, len ) ) != 0 )
460+
/* Do the initial seeding.
461+
* ctx->reseed_counter contains the desired amount of entropy to
462+
* grab for a nonce (see mbedtls_ctr_drbg_set_nonce_len()). */
463+
if( ( ret = mbedtls_ctr_drbg_reseed_internal( ctx, custom, len,
464+
ctx->reseed_counter ) ) != 0 )
416465
{
417466
return( ret );
418467
}

0 commit comments

Comments
 (0)