Message ID | 20220208155335.378318-2-Jason@zx2c4.com (mailing list archive) |
---|---|
State | Not Applicable |
Delegated to: | Herbert Xu |
Headers | show |
Series | random: cleanups around per-cpu crng & rdrand | expand |
On Tue, Feb 08, 2022 at 04:53:29PM +0100, Jason A. Donenfeld wrote: > When /dev/random was directly connected with entropy extraction, without > any expansion stage, extract_buf() was called for every 10 bytes of data > read from /dev/random. For that reason, RDRAND was used rather than > RDSEED. At the same time, crng_reseed() was still only called every 5 > minutes, so there RDSEED made sense. > > Those olden days were also a time when the entropy collector did not use > a cryptographic hash function, which meant most bets were off in terms > of real preimage resistance. For that reason too it didn't matter > _that_ much whether RDSEED was mixed in before or after entropy > extraction; both choices were sort of bad. > > But now we have a cryptographic hash function at work, and with that we > get real preimage resistance. We also now only call extract_entropy() > every 5 minutes, rather than every 10 bytes. This allows us to do two > important things. > > First, we can switch to using RDSEED in extract_entropy(), as Dominik > suggested. Second, we can ensure that RDSEED input always goes into the > cryptographic hash function with other things before being used > directly. This eliminates a category of attacks in which the CPU knows > the current state of the crng and knows that we're going to xor RDSEED > into it, and so it computes a malicious RDSEED. By going through our > hash function, it would require the CPU to compute a preimage on the > fly, which isn't going to happen. > > Cc: Theodore Ts'o <tytso@mit.edu> > Suggested-by: Dominik Brodowski <linux@dominikbrodowski.net> > Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> > --- > drivers/char/random.c | 22 +++++++++------------- > 1 file changed, 9 insertions(+), 13 deletions(-) Looks good, Reviewed-by: Eric Biggers <ebiggers@google.com> - Eric
diff --git a/drivers/char/random.c b/drivers/char/random.c index fe24d203b99b..42a3a3663767 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -722,13 +722,8 @@ static void crng_reseed(struct crng_state *crng) CHACHA_KEY_SIZE); } spin_lock_irqsave(&crng->lock, flags); - for (i = 0; i < 8; i++) { - unsigned long rv; - if (!arch_get_random_seed_long(&rv) && - !arch_get_random_long(&rv)) - rv = random_get_entropy(); - crng->state[i + 4] ^= buf.key[i] ^ rv; - } + for (i = 0; i < 8; i++) + crng->state[i + 4] ^= buf.key[i]; memzero_explicit(&buf, sizeof(buf)); WRITE_ONCE(crng->init_time, jiffies); spin_unlock_irqrestore(&crng->lock, flags); @@ -1064,16 +1059,17 @@ static void extract_entropy(void *buf, size_t nbytes) unsigned long flags; u8 seed[BLAKE2S_HASH_SIZE], next_key[BLAKE2S_HASH_SIZE]; struct { - unsigned long rdrand[32 / sizeof(long)]; + unsigned long rdseed[32 / sizeof(long)]; size_t counter; } block; size_t i; trace_extract_entropy(nbytes, input_pool.entropy_count); - for (i = 0; i < ARRAY_SIZE(block.rdrand); ++i) { - if (!arch_get_random_long(&block.rdrand[i])) - block.rdrand[i] = random_get_entropy(); + for (i = 0; i < ARRAY_SIZE(block.rdseed); ++i) { + if (!arch_get_random_seed_long(&block.rdseed[i]) && + !arch_get_random_long(&block.rdseed[i])) + block.rdseed[i] = random_get_entropy(); } spin_lock_irqsave(&input_pool.lock, flags); @@ -1081,7 +1077,7 @@ static void extract_entropy(void *buf, size_t nbytes) /* seed = HASHPRF(last_key, entropy_input) */ blake2s_final(&input_pool.hash, seed); - /* next_key = HASHPRF(seed, RDRAND || 0) */ + /* next_key = HASHPRF(seed, RDSEED || 0) */ block.counter = 0; blake2s(next_key, (u8 *)&block, seed, sizeof(next_key), sizeof(block), sizeof(seed)); blake2s_init_key(&input_pool.hash, BLAKE2S_HASH_SIZE, next_key, sizeof(next_key)); @@ -1091,7 +1087,7 @@ static void extract_entropy(void *buf, size_t nbytes) while (nbytes) { i = min_t(size_t, nbytes, BLAKE2S_HASH_SIZE); - /* output = HASHPRF(seed, RDRAND || ++counter) */ + /* output = HASHPRF(seed, RDSEED || ++counter) */ ++block.counter; blake2s(buf, (u8 *)&block, seed, i, sizeof(block), sizeof(seed)); nbytes -= i;
When /dev/random was directly connected with entropy extraction, without any expansion stage, extract_buf() was called for every 10 bytes of data read from /dev/random. For that reason, RDRAND was used rather than RDSEED. At the same time, crng_reseed() was still only called every 5 minutes, so there RDSEED made sense. Those olden days were also a time when the entropy collector did not use a cryptographic hash function, which meant most bets were off in terms of real preimage resistance. For that reason too it didn't matter _that_ much whether RDSEED was mixed in before or after entropy extraction; both choices were sort of bad. But now we have a cryptographic hash function at work, and with that we get real preimage resistance. We also now only call extract_entropy() every 5 minutes, rather than every 10 bytes. This allows us to do two important things. First, we can switch to using RDSEED in extract_entropy(), as Dominik suggested. Second, we can ensure that RDSEED input always goes into the cryptographic hash function with other things before being used directly. This eliminates a category of attacks in which the CPU knows the current state of the crng and knows that we're going to xor RDSEED into it, and so it computes a malicious RDSEED. By going through our hash function, it would require the CPU to compute a preimage on the fly, which isn't going to happen. Cc: Theodore Ts'o <tytso@mit.edu> Suggested-by: Dominik Brodowski <linux@dominikbrodowski.net> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> --- drivers/char/random.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-)