diff --git a/library/bignum_mod_raw.c b/library/bignum_mod_raw.c index c98a1c1cbf..fbd90bf22d 100644 --- a/library/bignum_mod_raw.c +++ b/library/bignum_mod_raw.c @@ -176,6 +176,18 @@ void mbedtls_mpi_mod_raw_add( mbedtls_mpi_uint *X, /* BEGIN MERGE SLOT 6 */ +int mbedtls_mpi_mod_raw_random( mbedtls_mpi_uint *X, + mbedtls_mpi_uint min, + const mbedtls_mpi_mod_modulus *N, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret = mbedtls_mpi_core_random( X, min, N->p, N->limbs, f_rng, p_rng ); + if( ret != 0 ) + return( ret ); + return( mbedtls_mpi_mod_raw_to_mont_rep( X, N ) ); +} + /* END MERGE SLOT 6 */ /* BEGIN MERGE SLOT 7 */ diff --git a/library/bignum_mod_raw.h b/library/bignum_mod_raw.h index e6237b3593..87e241fa5c 100644 --- a/library/bignum_mod_raw.h +++ b/library/bignum_mod_raw.h @@ -297,6 +297,40 @@ void mbedtls_mpi_mod_raw_add( mbedtls_mpi_uint *X, /* BEGIN MERGE SLOT 6 */ +/** Generate a random number uniformly in a range. + * + * This function generates a random number between \p min inclusive and + * \p N exclusive. + * + * The procedure complies with RFC 6979 ยง3.3 (deterministic ECDSA) + * when the RNG is a suitably parametrized instance of HMAC_DRBG + * and \p min is \c 1. + * + * \note There are `N - min` possible outputs. The lower bound + * \p min can be reached, but the upper bound \p N cannot. + * + * \param X The destination MPI, in canonical representation modulo \p N. + * It must not be aliased with \p N or otherwise overlap it. + * \param min The minimum value to return. It must be strictly smaller + * than \b N. + * \param N The modulus. + * This is the upper bound of the output range, exclusive. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if the implementation was + * unable to find a suitable value within a limited number + * of attempts. This has a negligible probability if \p N + * is significantly larger than \p min, which is the case + * for all usual cryptographic applications. + */ +int mbedtls_mpi_mod_raw_random( mbedtls_mpi_uint *X, + mbedtls_mpi_uint min, + const mbedtls_mpi_mod_modulus *N, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + /* END MERGE SLOT 6 */ /* BEGIN MERGE SLOT 7 */ diff --git a/tests/suites/test_suite_bignum_random.data b/tests/suites/test_suite_bignum_random.data index bf51b0f0a5..b51254b5a3 100644 --- a/tests/suites/test_suite_bignum_random.data +++ b/tests/suites/test_suite_bignum_random.data @@ -17,31 +17,43 @@ MPI core random basic: 2^30..2^129 mpi_core_random_basic:0x40000000:"0200000000000000000000000000000000":0 # Use the same data values for mpi_core_random_basic->NOT_ACCEPTABLE -# and for mpi_legacy_random_values where we want to return NOT_ACCEPTABLE +# and for mpi_XXX_random_values where we want to return NOT_ACCEPTABLE # but this isn't checked at runtime. -MPI core random basic: 2^28-1..2^28 (NOT_ACCEPTABLE) -mpi_core_random_basic:0x0fffffff:"10000000":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE +MPI core random basic: 2^28-1..2^28+1 (NOT_ACCEPTABLE) +mpi_core_random_basic:0x0fffffff:"10000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE -MPI random legacy=core: 2^28-1..2^28 (NOT_ACCEPTABLE) -mpi_legacy_random_values:0x0fffffff:"10000000" +MPI random legacy=core: 2^28-1..2^28+1 (NOT_ACCEPTABLE) +mpi_legacy_random_values:0x0fffffff:"10000001" -MPI core random basic: 2^29-1..2^29 (NOT_ACCEPTABLE) -mpi_core_random_basic:0x1fffffff:"20000000":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE +MPI random mod=core: 2^28-1..2^28+1 (NOT_ACCEPTABLE) +mpi_mod_random_values:0x0fffffff:"10000001" -MPI random legacy=core: 2^29-1..2^29 (NOT_ACCEPTABLE) -mpi_legacy_random_values:0x1fffffff:"20000000" +MPI core random basic: 2^29-1..2^29+1 (NOT_ACCEPTABLE) +mpi_core_random_basic:0x1fffffff:"20000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE -MPI core random basic: 2^30-1..2^30 (NOT_ACCEPTABLE) -mpi_core_random_basic:0x3fffffff:"40000000":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE +MPI random legacy=core: 2^29-1..2^29+1 (NOT_ACCEPTABLE) +mpi_legacy_random_values:0x1fffffff:"20000001" -MPI random legacy=core: 2^30-1..2^30 (NOT_ACCEPTABLE) -mpi_legacy_random_values:0x3fffffff:"40000000" +MPI random mod=core: 2^29-1..2^29+1 (NOT_ACCEPTABLE) +mpi_mod_random_values:0x1fffffff:"20000001" -MPI core random basic: 2^31-1..2^31 (NOT_ACCEPTABLE) -mpi_core_random_basic:0x7fffffff:"80000000":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE +MPI core random basic: 2^30-1..2^30+1 (NOT_ACCEPTABLE) +mpi_core_random_basic:0x3fffffff:"40000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE -MPI random legacy=core: 2^31-1..2^31 (NOT_ACCEPTABLE) -mpi_legacy_random_values:0x7fffffff:"80000000" +MPI random legacy=core: 2^30-1..2^30+1 (NOT_ACCEPTABLE) +mpi_legacy_random_values:0x3fffffff:"40000001" + +MPI random mod=core: 2^30-1..2^30+1 (NOT_ACCEPTABLE) +mpi_mod_random_values:0x3fffffff:"40000001" + +MPI core random basic: 2^31-1..2^31+1 (NOT_ACCEPTABLE) +mpi_core_random_basic:0x7fffffff:"80000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE + +MPI random legacy=core: 2^31-1..2^31+1 (NOT_ACCEPTABLE) +mpi_legacy_random_values:0x7fffffff:"80000001" + +MPI random mod=core: 2^31-1..2^31+1 (NOT_ACCEPTABLE) +mpi_mod_random_values:0x7fffffff:"80000001" MPI random in range: 1..2 mpi_random_many:1:"02":1000 @@ -233,3 +245,21 @@ mpi_legacy_random_values:0:"0100000000000000000000000000000000000000000000000000 MPI random legacy=core: 0..2^256+1 mpi_legacy_random_values:0:"010000000000000000000000000000000000000000000000000000000000000001" + +MPI random mod=core: 0..1 +mpi_mod_random_values:0:"01" + +MPI random mod=core: 0..3 +mpi_mod_random_values:0:"03" + +MPI random mod=core: 1..3 +mpi_mod_random_values:1:"03" + +MPI random mod=core: 2^30..2^31-1 +mpi_mod_random_values:0x40000000:"7fffffff" + +MPI random mod=core: 2^31-1..2^32-1 +mpi_mod_random_values:0x7fffffff:"ffffffff" + +MPI random mod=core: 0..2^256+1 +mpi_mod_random_values:0:"010000000000000000000000000000000000000000000000000000000000000001" diff --git a/tests/suites/test_suite_bignum_random.function b/tests/suites/test_suite_bignum_random.function index 2250e8c5de..a837e1b04b 100644 --- a/tests/suites/test_suite_bignum_random.function +++ b/tests/suites/test_suite_bignum_random.function @@ -8,6 +8,7 @@ #include "mbedtls/bignum.h" #include "mbedtls/entropy.h" #include "bignum_core.h" +#include "bignum_mod_raw.h" #include "constant_time_internal.h" /* This test suite only manipulates non-negative bignums. */ @@ -158,6 +159,61 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void mpi_mod_random_values( int min, char *max_hex ) +{ + /* Same RNG as in mpi_core_random_basic */ + mbedtls_test_rnd_pseudo_info rnd_core = { + {'T', 'h', 'i', 's', ' ', 'i', ',', 'a', + 's', 'e', 'e', 'd', '!', 0}, + 0, 0}; + mbedtls_test_rnd_pseudo_info rnd_mod_raw; + memcpy( &rnd_mod_raw, &rnd_core, sizeof( rnd_core ) ); + mbedtls_mpi_uint *R_core = NULL; + mbedtls_mpi_uint *R_mod_raw = NULL; + mbedtls_mpi_mod_modulus N; + mbedtls_mpi_mod_modulus_init( &N ); + + TEST_EQUAL( mbedtls_test_read_mpi_modulus( &N, max_hex, + MBEDTLS_MPI_MOD_REP_MONTGOMERY ), + 0 ); + ASSERT_ALLOC( R_core, N.limbs ); + ASSERT_ALLOC( R_mod_raw, N.limbs ); + + /* Call the core and mod random() functions with the same random stream. */ + int core_ret = mbedtls_mpi_core_random( R_core, + min, N.p, N.limbs, + mbedtls_test_rnd_pseudo_rand, + &rnd_core ); + int mod_raw_ret = mbedtls_mpi_mod_raw_random( R_mod_raw, + min, &N, + mbedtls_test_rnd_pseudo_rand, + &rnd_mod_raw ); + + /* They must return the same status, and, on success, output the + * same number, with the same limb count. */ + TEST_EQUAL( core_ret, mod_raw_ret ); + if( core_ret == 0 ) + { + TEST_EQUAL( mbedtls_mpi_mod_raw_from_mont_rep( R_mod_raw, &N ), 0 ); + ASSERT_COMPARE( R_core, N.limbs * ciL, + R_mod_raw, N.limbs * ciL ); + } + + /* Also check that they have consumed the RNG in the same way. */ + /* This may theoretically fail on rare platforms with padding in + * the structure! If this is a problem in practice, change to a + * field-by-field comparison. */ + ASSERT_COMPARE( &rnd_core, sizeof( rnd_core ), + &rnd_mod_raw, sizeof( rnd_mod_raw ) ); + +exit: + mbedtls_mpi_mod_modulus_free( &N ); + mbedtls_free( R_core ); + mbedtls_free( R_mod_raw ); +} +/* END_CASE */ + /* BEGIN_CASE */ void mpi_random_many( int min, char *bound_hex, int iterations ) {