diff options
author | David Goulet <dgoulet@torproject.org> | 2019-04-30 11:17:45 -0400 |
---|---|---|
committer | David Goulet <dgoulet@torproject.org> | 2019-04-30 11:17:45 -0400 |
commit | e543c4e20c50035df61cdfaae75ee4dbb61409bf (patch) | |
tree | 3a36462ee3965801585ba7a6d7a989a89587bef3 /src/lib/crypt_ops | |
parent | 44e6663b8a51187e80a3f94d1185950cf62b4264 (diff) | |
parent | 48e1ab17204944e6197002dfa3d3d0c8a08184dc (diff) | |
download | tor-e543c4e20c50035df61cdfaae75ee4dbb61409bf.tar.gz tor-e543c4e20c50035df61cdfaae75ee4dbb61409bf.zip |
Merge branch 'tor-github/pr/909'
Signed-off-by: David Goulet <dgoulet@torproject.org>
Diffstat (limited to 'src/lib/crypt_ops')
-rw-r--r-- | src/lib/crypt_ops/crypto_rand.h | 4 | ||||
-rw-r--r-- | src/lib/crypt_ops/crypto_rand_fast.c | 82 |
2 files changed, 69 insertions, 17 deletions
diff --git a/src/lib/crypt_ops/crypto_rand.h b/src/lib/crypt_ops/crypto_rand.h index c51d6a4480..528f238fa5 100644 --- a/src/lib/crypt_ops/crypto_rand.h +++ b/src/lib/crypt_ops/crypto_rand.h @@ -92,6 +92,10 @@ void crypto_rand_fast_shutdown(void); #if defined(TOR_UNIT_TESTS) /* Used for white-box testing */ size_t crypto_fast_rng_get_bytes_used_per_stream(void); +/* For deterministic prng implementations */ +void crypto_fast_rng_disable_reseed(crypto_fast_rng_t *rng); +/* To override the prng for testing. */ +crypto_fast_rng_t *crypto_replace_thread_fast_rng(crypto_fast_rng_t *rng); #endif #ifdef CRYPTO_RAND_PRIVATE diff --git a/src/lib/crypt_ops/crypto_rand_fast.c b/src/lib/crypt_ops/crypto_rand_fast.c index 01817c618f..b71ade81bd 100644 --- a/src/lib/crypt_ops/crypto_rand_fast.c +++ b/src/lib/crypt_ops/crypto_rand_fast.c @@ -95,8 +95,13 @@ CTASSERT(KEY_BITS == 128 || KEY_BITS == 192 || KEY_BITS == 256); struct crypto_fast_rng_t { /** How many more fills does this buffer have before we should mix - * in the output of crypto_rand()? */ - uint16_t n_till_reseed; + * in the output of crypto_strongest_rand()? + * + * This value may be negative if unit tests are enabled. If so, it + * indicates that we should never mix in extra data from + * crypto_strongest_rand(). + */ + int16_t n_till_reseed; /** How many bytes are remaining in cbuf.bytes? */ uint16_t bytes_left; #ifdef CHECK_PID @@ -181,6 +186,18 @@ crypto_fast_rng_new_from_seed(const uint8_t *seed) return result; } +#ifdef TOR_UNIT_TESTS +/** + * Unit tests only: prevent a crypto_fast_rng_t from ever mixing in more + * entropy. + */ +void +crypto_fast_rng_disable_reseed(crypto_fast_rng_t *rng) +{ + rng->n_till_reseed = -1; +} +#endif + /** * Helper: create a crypto_cipher_t object from SEED_LEN bytes of * input. The first KEY_LEN bytes are used as the stream cipher's key, @@ -193,6 +210,26 @@ cipher_from_seed(const uint8_t *seed) } /** + * Helper: mix additional entropy into <b>rng</b> by using our XOF to mix the + * old value for the seed with some additional bytes from + * crypto_strongest_rand(). + **/ +static void +crypto_fast_rng_add_entopy(crypto_fast_rng_t *rng) +{ + crypto_xof_t *xof = crypto_xof_new(); + crypto_xof_add_bytes(xof, rng->buf.seed, SEED_LEN); + { + uint8_t seedbuf[SEED_LEN]; + crypto_strongest_rand(seedbuf, SEED_LEN); + crypto_xof_add_bytes(xof, seedbuf, SEED_LEN); + memwipe(seedbuf, 0, SEED_LEN); + } + crypto_xof_squeeze_bytes(xof, rng->buf.seed, SEED_LEN); + crypto_xof_free(xof); +} + +/** * Helper: refill the seed bytes and output buffer of <b>rng</b>, using * the input seed bytes as input (key and IV) for the stream cipher. * @@ -202,22 +239,19 @@ cipher_from_seed(const uint8_t *seed) static void crypto_fast_rng_refill(crypto_fast_rng_t *rng) { - if (rng->n_till_reseed-- == 0) { - /* It's time to reseed the RNG. We'll do this by using our XOF to mix the - * old value for the seed with some additional bytes from - * crypto_strongest_rand(). */ - crypto_xof_t *xof = crypto_xof_new(); - crypto_xof_add_bytes(xof, rng->buf.seed, SEED_LEN); - { - uint8_t seedbuf[SEED_LEN]; - crypto_strongest_rand(seedbuf, SEED_LEN); - crypto_xof_add_bytes(xof, seedbuf, SEED_LEN); - memwipe(seedbuf, 0, SEED_LEN); - } - crypto_xof_squeeze_bytes(xof, rng->buf.seed, SEED_LEN); - crypto_xof_free(xof); - + rng->n_till_reseed--; + if (rng->n_till_reseed == 0) { + /* It's time to reseed the RNG. */ + crypto_fast_rng_add_entopy(rng); rng->n_till_reseed = RESEED_AFTER; + } else if (rng->n_till_reseed < 0) { +#ifdef TOR_UNIT_TESTS + /* Reseeding is disabled for testing; never do it on this prng. */ + rng->n_till_reseed = -1; +#else + /* If testing is disabled, this shouldn't be able to become negative. */ + tor_assert_unreached(); +#endif } /* Now fill rng->buf with output from our stream cipher, initialized from * that seed value. */ @@ -363,6 +397,20 @@ destroy_thread_fast_rng(void) tor_threadlocal_set(&thread_rng, NULL); } +#ifdef TOR_UNIT_TESTS +/** + * Replace the current thread's rng with <b>rng</b>. For use by the + * unit tests only. Returns the previous thread rng. + **/ +crypto_fast_rng_t * +crypto_replace_thread_fast_rng(crypto_fast_rng_t *rng) +{ + crypto_fast_rng_t *old_rng = tor_threadlocal_get(&thread_rng); + tor_threadlocal_set(&thread_rng, rng); + return old_rng; +} +#endif + /** * Initialize the global thread-local key that will be used to keep track * of per-thread fast RNG instances. Called from the crypto subsystem's |