2022-04-07 14:38:55

by Sandy Harris

[permalink] [raw]
Subject: Re: [PATCH] random: opportunistically initialize on /dev/urandom reads

Does this help?

I have some code I'm not yet ready to submit as patches. Here's some
of it that could be used to initialise the pool (& I think also the
counter for chacha). The paper linked in the comments suggests that
adding a bit reversal would improve diffusion, but I have not done
that yet.

/**************************************************************************
* Load a 64-bit word with data from whatever source we have
*
* arch_get_random_long()
* hardware RNG
* emulated HWRNG in a VM
*
* When there are two sources, alternate.
*
* If you have no better source, or if one fails,
* or if the argument 'fast' is set, then fall back
* to random_get_entropy().
*
* Also use random_get_entropy() sometimes even
* if we have a good source, to avoid trusting
* the source completely
***************************************************************************/

static int load_count = 0;
static spinlock_t source_lock;
static unsigned long source_value __latent_entropy ;

#define rotl64(x,n) ((x>>(n)) | (x<<(n)))

static int get_hw_long(unsigned long *x)
{
int ret ;
unsigned s = sizeof(unsigned long) ;
ret = get_random_bytes_arch((u8 *) x, s) ;
return (ret == s) ? 1 : 0 ;
}

/* This should be a Mersenne number, (2^x)-1 */
#define MIX_MASK 15

#define GOT_A IS_ENABLED(CONFIG_ARCH_RANDOM)
#define GOT_H IS_ENABLED(CONFIG_HW_RANDOM)

static unsigned long get_64(int fast)
{
int ret = 0 ;
unsigned long x, flags ;

if (!fast && (GOT_A||GOT_H) && (load_count&MIX_MASK)) {
if (GOT_A && GOT_H) {
if (load_count & 1)
ret = arch_get_random_long(&x) ;
else ret = get_hw_long(&x) ;
/*
* if the chosen source failed
* then try the other
*/
if (!ret)
if (load_count & 1)
ret = get_hw_long(&x) ;
else ret = arch_get_random_long(&x) ;
}
if (GOT_A && !GOT_H)
ret = arch_get_random_long(&x) ;
if (GOT_H && !GOT_A)
ret = get_hw_long(&x) ;
}
/*
* fast is nonzero, so not trying expensive methods
*
* or no source configured, neither GOT_A nor GOT_H set
* or configured one(s) failed, ret is still zero
*
* or it is just time for a different source
* (load_count&MIX_MASK) == 0
*/
if (!ret)
x = random_get_entropy() ;
/*
* use 19-bit rotation, based on
* https://eprint.iacr.org/2021/523.pdf
*/
spin_lock_irqsave(&source_lock, flags);
source_value = rotl64(source_value, 19) ^ x ;
load_count++ ;
spin_unlock_irqrestore(&source_lock, flags);
memzero_explicit(x, sizeof(x)) ;
return(source_value) ;
}