On 2017/10/17 22:12, Christian Weisgerber wrote:
> The /dev/arandom device was a detour that we are trying to get rid
> of. Nothing should use it any longer. Code should preferably use
> the arc4random() family of functions to get random numbers. If
> that isn't an option, e.g. in shell, use /dev/urandom.
>
> I extracted all packages from an amd64 snapshot and ran fgrep -a
> /dev/arandom over all files. It turned up these matches:
A common method is to try various /dev/*random nodes in order to find
one which works. In some cases this is done at configure time, in others
at runtime.
To pick one example, nmap:
------------
void nrand_init(nrand_h *r) {
u8 seed[256]; /* Starts out with "random" stack data */
int i;
/* Gather seed entropy with best the OS has to offer */
#ifdef WIN32
HCRYPTPROV hcrypt = 0;
CryptAcquireContext(&hcrypt, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
CryptGenRandom(hcrypt, sizeof(seed), seed);
CryptReleaseContext(hcrypt, 0);
#else
struct timeval *tv = (struct timeval *)seed;
int *pid = (int *)(seed + sizeof(*tv));
int fd;
gettimeofday(tv, NULL); /* fill lowest seed[] with time */
*pid = getpid(); /* fill next lowest seed[] with pid */
/* Try to fill the rest of the state with OS provided entropy */
if ((fd = open("/dev/urandom", O_RDONLY)) != -1 ||
(fd = open("/dev/arandom", O_RDONLY)) != -1) {
ssize_t n;
do {
errno = 0;
n = read(fd, seed + sizeof(*tv) + sizeof(*pid),
sizeof(seed) - sizeof(*tv) - sizeof(*pid));
} while (n < 0 && errno == EINTR);
close(fd);
}
#endif
/* Fill up our handle with starter values */
for (i = 0; i < 256; i++) { r->s[i] = i; };
r->i = r->j = 0;
nrand_addrandom(r, seed, 128); /* lower half of seed data for entropy */
nrand_addrandom(r, seed + 128, 128); /* Now use upper half */
r->tmp = NULL;
r->tmplen = 0;
/* This stream will start biased. Get rid of 1K of the stream */
nrand_get(r, seed, 256); nrand_get(r, seed, 256);
nrand_get(r, seed, 256); nrand_get(r, seed, 256);
}
int get_random_bytes(void *buf, int numbytes) {
static nrand_h state;
static int state_init = 0;
/* Initialize if we need to */
if (!state_init) {
nrand_init(&state);
state_init = 1;
}
/* Now fill our buffer */
nrand_get(&state, buf, numbytes);
return 0;
}
------------
In this case, I'd consider converting get_random_bytes() to use
arc4random_buf, and get rid of nrand_init which is only called from
get_random_bytes. The other get_random_* are implemented in terms of
get_random_bytes and should get_random_probably just be left alone
(especially the LCG in get_random_unique_u32).
That list of files is shorter than I would have guessed :)