mirror of
https://github.com/torvalds/linux.git
synced 2026-06-07 05:55:44 +02:00
random: use RDSEED instead of RDRAND in entropy extraction
commit 28f425e573 upstream.
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>
Reviewed-by: Eric Biggers <ebiggers@google.com>
Reviewed-by: Dominik Brodowski <linux@dominikbrodowski.net>
Suggested-by: Dominik Brodowski <linux@dominikbrodowski.net>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
1d1582e5fe
commit
c36e71b5a5
|
|
@ -727,13 +727,8 @@ static void crng_reseed(struct crng_state *crng)
|
||||||
CHACHA_KEY_SIZE);
|
CHACHA_KEY_SIZE);
|
||||||
}
|
}
|
||||||
spin_lock_irqsave(&crng->lock, flags);
|
spin_lock_irqsave(&crng->lock, flags);
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++)
|
||||||
unsigned long rv;
|
crng->state[i + 4] ^= buf.key[i];
|
||||||
if (!arch_get_random_seed_long(&rv) &&
|
|
||||||
!arch_get_random_long(&rv))
|
|
||||||
rv = random_get_entropy();
|
|
||||||
crng->state[i + 4] ^= buf.key[i] ^ rv;
|
|
||||||
}
|
|
||||||
memzero_explicit(&buf, sizeof(buf));
|
memzero_explicit(&buf, sizeof(buf));
|
||||||
WRITE_ONCE(crng->init_time, jiffies);
|
WRITE_ONCE(crng->init_time, jiffies);
|
||||||
spin_unlock_irqrestore(&crng->lock, flags);
|
spin_unlock_irqrestore(&crng->lock, flags);
|
||||||
|
|
@ -1054,16 +1049,17 @@ static void extract_entropy(void *buf, size_t nbytes)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u8 seed[BLAKE2S_HASH_SIZE], next_key[BLAKE2S_HASH_SIZE];
|
u8 seed[BLAKE2S_HASH_SIZE], next_key[BLAKE2S_HASH_SIZE];
|
||||||
struct {
|
struct {
|
||||||
unsigned long rdrand[32 / sizeof(long)];
|
unsigned long rdseed[32 / sizeof(long)];
|
||||||
size_t counter;
|
size_t counter;
|
||||||
} block;
|
} block;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
trace_extract_entropy(nbytes, input_pool.entropy_count);
|
trace_extract_entropy(nbytes, input_pool.entropy_count);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(block.rdrand); ++i) {
|
for (i = 0; i < ARRAY_SIZE(block.rdseed); ++i) {
|
||||||
if (!arch_get_random_long(&block.rdrand[i]))
|
if (!arch_get_random_seed_long(&block.rdseed[i]) &&
|
||||||
block.rdrand[i] = random_get_entropy();
|
!arch_get_random_long(&block.rdseed[i]))
|
||||||
|
block.rdseed[i] = random_get_entropy();
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&input_pool.lock, flags);
|
spin_lock_irqsave(&input_pool.lock, flags);
|
||||||
|
|
@ -1071,7 +1067,7 @@ static void extract_entropy(void *buf, size_t nbytes)
|
||||||
/* seed = HASHPRF(last_key, entropy_input) */
|
/* seed = HASHPRF(last_key, entropy_input) */
|
||||||
blake2s_final(&input_pool.hash, seed);
|
blake2s_final(&input_pool.hash, seed);
|
||||||
|
|
||||||
/* next_key = HASHPRF(seed, RDRAND || 0) */
|
/* next_key = HASHPRF(seed, RDSEED || 0) */
|
||||||
block.counter = 0;
|
block.counter = 0;
|
||||||
blake2s(next_key, (u8 *)&block, seed, sizeof(next_key), sizeof(block), sizeof(seed));
|
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));
|
blake2s_init_key(&input_pool.hash, BLAKE2S_HASH_SIZE, next_key, sizeof(next_key));
|
||||||
|
|
@ -1081,7 +1077,7 @@ static void extract_entropy(void *buf, size_t nbytes)
|
||||||
|
|
||||||
while (nbytes) {
|
while (nbytes) {
|
||||||
i = min_t(size_t, nbytes, BLAKE2S_HASH_SIZE);
|
i = min_t(size_t, nbytes, BLAKE2S_HASH_SIZE);
|
||||||
/* output = HASHPRF(seed, RDRAND || ++counter) */
|
/* output = HASHPRF(seed, RDSEED || ++counter) */
|
||||||
++block.counter;
|
++block.counter;
|
||||||
blake2s(buf, (u8 *)&block, seed, i, sizeof(block), sizeof(seed));
|
blake2s(buf, (u8 *)&block, seed, i, sizeof(block), sizeof(seed));
|
||||||
nbytes -= i;
|
nbytes -= i;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user