Skip to content

Commit 9f9eff8

Browse files
committed
random: use BLAKE2s instead of SHA1 in extraction
This commit addresses one of the lower hanging fruits of the RNG: its usage of SHA1. BLAKE2s is generally faster, and certainly more secure, than SHA1, which has [1] been [2] really [3] very [4] broken [5]. Additionally, the current construction in the RNG doesn't use the full SHA1 function, as specified, and allows overwriting the IV with RDRAND output in an undocumented way, even in the case when RDRAND isn't set to "trusted", which means potential malicious IV choices. And its short length means that keeping only half of it secret when feeding back into the mixer gives us only 2^80 bits of forward secrecy. In other words, not only is the choice of hash function dated, but the use of it isn't really great either. This commit aims to fix both of these issues while also keeping the general structure and semantics as close to the original as possible. Specifically: a) Rather than overwriting the hash IV with RDRAND, we put it into BLAKE2's documented "salt" and "personal" fields, which were specifically created for this type of usage. b) Since this function feeds the full hash result back into the entropy collector, we only return from it half the length of the hash, just as it was done before. This increases the construction's forward secrecy from 2^80 to a much more comfortable 2^128. c) Rather than using the raw "sha1_transform" function alone, we instead use the full proper BLAKE2s function, with finalization. This also has the advantage of supplying 16 bytes at a time rather than SHA1's 10 bytes, which, in addition to having a faster compression function to begin with, means faster extraction in general. On an Intel i7-11850H, this commit makes initial seeding around 131% faster. BLAKE2s itself has the nice property of internally being based on the ChaCha permutation, which the RNG is already using for expansion, so there shouldn't be any issue with newness, funkiness, or surprising CPU behavior, since it's based on something already in use. [1] https://eprint.iacr.org/2005/010.pdf [2] https://www.iacr.org/archive/crypto2005/36210017/36210017.pdf [3] https://eprint.iacr.org/2015/967.pdf [4] https://shattered.io/static/shattered.pdf [5] https://www.usenix.org/system/files/sec20-leurent.pdf Reviewed-by: Theodore Ts'o <[email protected]> Reviewed-by: Eric Biggers <[email protected]> Reviewed-by: Greg Kroah-Hartman <[email protected]> Reviewed-by: Jean-Philippe Aumasson <[email protected]> Signed-off-by: Jason A. Donenfeld <[email protected]>
1 parent 6048fdc commit 9f9eff8

File tree

1 file changed

+30
-41
lines changed

1 file changed

+30
-41
lines changed

drivers/char/random.c

Lines changed: 30 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
/*
22
* random.c -- A strong random number generator
33
*
4-
* Copyright (C) 2017 Jason A. Donenfeld <[email protected]>. All
5-
* Rights Reserved.
4+
* Copyright (C) 2017-2022 Jason A. Donenfeld <[email protected]>. All Rights Reserved.
65
*
76
* Copyright Matt Mackall <[email protected]>, 2003, 2004, 2005
87
*
@@ -78,12 +77,12 @@
7877
* an *estimate* of how many bits of randomness have been stored into
7978
* the random number generator's internal state.
8079
*
81-
* When random bytes are desired, they are obtained by taking the SHA
82-
* hash of the contents of the "entropy pool". The SHA hash avoids
80+
* When random bytes are desired, they are obtained by taking the BLAKE2s
81+
* hash of the contents of the "entropy pool". The BLAKE2s hash avoids
8382
* exposing the internal state of the entropy pool. It is believed to
8483
* be computationally infeasible to derive any useful information
85-
* about the input of SHA from its output. Even if it is possible to
86-
* analyze SHA in some clever way, as long as the amount of data
84+
* about the input of BLAKE2s from its output. Even if it is possible to
85+
* analyze BLAKE2s in some clever way, as long as the amount of data
8786
* returned from the generator is less than the inherent entropy in
8887
* the pool, the output data is totally unpredictable. For this
8988
* reason, the routine decreases its internal estimate of how many
@@ -93,7 +92,7 @@
9392
* If this estimate goes to zero, the routine can still generate
9493
* random numbers; however, an attacker may (at least in theory) be
9594
* able to infer the future output of the generator from prior
96-
* outputs. This requires successful cryptanalysis of SHA, which is
95+
* outputs. This requires successful cryptanalysis of BLAKE2s, which is
9796
* not believed to be feasible, but there is a remote possibility.
9897
* Nonetheless, these numbers should be useful for the vast majority
9998
* of purposes.
@@ -347,7 +346,7 @@
347346
#include <linux/completion.h>
348347
#include <linux/uuid.h>
349348
#include <crypto/chacha.h>
350-
#include <crypto/sha1.h>
349+
#include <crypto/blake2s.h>
351350

352351
#include <asm/processor.h>
353352
#include <linux/uaccess.h>
@@ -367,10 +366,7 @@
367366
#define INPUT_POOL_WORDS (1 << (INPUT_POOL_SHIFT-5))
368367
#define OUTPUT_POOL_SHIFT 10
369368
#define OUTPUT_POOL_WORDS (1 << (OUTPUT_POOL_SHIFT-5))
370-
#define EXTRACT_SIZE 10
371-
372-
373-
#define LONGS(x) (((x) + sizeof(unsigned long) - 1)/sizeof(unsigned long))
369+
#define EXTRACT_SIZE (BLAKE2S_HASH_SIZE / 2)
374370

375371
/*
376372
* To allow fractional bits to be tracked, the entropy_count field is
@@ -406,7 +402,7 @@ static int random_write_wakeup_bits = 28 * OUTPUT_POOL_WORDS;
406402
* Thanks to Colin Plumb for suggesting this.
407403
*
408404
* The mixing operation is much less sensitive than the output hash,
409-
* where we use SHA-1. All that we want of mixing operation is that
405+
* where we use BLAKE2s. All that we want of mixing operation is that
410406
* it be a good non-cryptographic hash; i.e. it not produce collisions
411407
* when fed "random" data of the sort we expect to see. As long as
412408
* the pool state differs for different inputs, we have preserved the
@@ -1384,56 +1380,49 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min,
13841380
*/
13851381
static void extract_buf(struct entropy_store *r, __u8 *out)
13861382
{
1387-
int i;
1388-
union {
1389-
__u32 w[5];
1390-
unsigned long l[LONGS(20)];
1391-
} hash;
1392-
__u32 workspace[SHA1_WORKSPACE_WORDS];
1383+
struct blake2s_state state __aligned(__alignof__(unsigned long));
1384+
u8 hash[BLAKE2S_HASH_SIZE];
1385+
unsigned long *salt;
13931386
unsigned long flags;
13941387

1388+
blake2s_init(&state, sizeof(hash));
1389+
13951390
/*
13961391
* If we have an architectural hardware random number
1397-
* generator, use it for SHA's initial vector
1392+
* generator, use it for BLAKE2's salt & personal fields.
13981393
*/
1399-
sha1_init(hash.w);
1400-
for (i = 0; i < LONGS(20); i++) {
1394+
for (salt = (unsigned long *)&state.h[4];
1395+
salt < (unsigned long *)&state.h[8]; ++salt) {
14011396
unsigned long v;
14021397
if (!arch_get_random_long(&v))
14031398
break;
1404-
hash.l[i] = v;
1399+
*salt ^= v;
14051400
}
14061401

1407-
/* Generate a hash across the pool, 16 words (512 bits) at a time */
1402+
/* Generate a hash across the pool */
14081403
spin_lock_irqsave(&r->lock, flags);
1409-
for (i = 0; i < r->poolinfo->poolwords; i += 16)
1410-
sha1_transform(hash.w, (__u8 *)(r->pool + i), workspace);
1404+
blake2s_update(&state, (const u8 *)r->pool,
1405+
r->poolinfo->poolwords * sizeof(*r->pool));
1406+
blake2s_final(&state, hash); /* final zeros out state */
14111407

14121408
/*
14131409
* We mix the hash back into the pool to prevent backtracking
14141410
* attacks (where the attacker knows the state of the pool
14151411
* plus the current outputs, and attempts to find previous
1416-
* ouputs), unless the hash function can be inverted. By
1417-
* mixing at least a SHA1 worth of hash data back, we make
1412+
* outputs), unless the hash function can be inverted. By
1413+
* mixing at least a hash worth of hash data back, we make
14181414
* brute-forcing the feedback as hard as brute-forcing the
14191415
* hash.
14201416
*/
1421-
__mix_pool_bytes(r, hash.w, sizeof(hash.w));
1417+
__mix_pool_bytes(r, hash, sizeof(hash));
14221418
spin_unlock_irqrestore(&r->lock, flags);
14231419

1424-
memzero_explicit(workspace, sizeof(workspace));
1425-
1426-
/*
1427-
* In case the hash function has some recognizable output
1428-
* pattern, we fold it in half. Thus, we always feed back
1429-
* twice as much data as we output.
1420+
/* Note that EXTRACT_SIZE is half of hash size here, because above
1421+
* we've dumped the full length back into mixer. By reducing the
1422+
* amount that we emit, we retain a level of forward secrecy.
14301423
*/
1431-
hash.w[0] ^= hash.w[3];
1432-
hash.w[1] ^= hash.w[4];
1433-
hash.w[2] ^= rol32(hash.w[2], 16);
1434-
1435-
memcpy(out, &hash, EXTRACT_SIZE);
1436-
memzero_explicit(&hash, sizeof(hash));
1424+
memcpy(out, hash, EXTRACT_SIZE);
1425+
memzero_explicit(hash, sizeof(hash));
14371426
}
14381427

14391428
static ssize_t _extract_entropy(struct entropy_store *r, void *buf,

0 commit comments

Comments
 (0)