Skip to content

Commit

Permalink
lib: Use best available random number generator
Browse files Browse the repository at this point in the history
The best available method is used from short list of
getrandom, arc4random or reading /dev/urandom
  • Loading branch information
cmouse authored and Timo Sirainen committed Sep 7, 2017
1 parent 5405ee4 commit 8045f6e
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 38 deletions.
70 changes: 38 additions & 32 deletions src/lib/randgen.c
Expand Up @@ -6,28 +6,56 @@
#include <unistd.h>
#include <fcntl.h>

/* get randomness from either getrandom, arc4random or /dev/urandom */

#if defined(HAVE_GETRANDOM) && HAVE_DECL_GETRANDOM != 0
# include <sys/random.h>
# define USE_GETRANDOM
#elif defined(HAVE_ARC4RANDOM)
# if defined(HAVE_LIBBSD)
# include <bsd/stdlib.h>
# endif
# define USE_ARC4RANDOM
#else
# define USE_RANDOM_DEV
#endif

static int init_refcount = 0;
#if defined(USE_RANDOM_DEV)
static int urandom_fd;
#endif

void random_fill(void *buf, size_t size)
{
size_t pos;
ssize_t ret;

i_assert(init_refcount > 0);
i_assert(size < SSIZE_T_MAX);

#if defined(USE_ARC4RANDOM)
arc4random_buf(buf, size);
#else
size_t pos;
ssize_t ret;

for (pos = 0; pos < size; ) {
# if defined(USE_GETRANDOM)
ret = getrandom(buf, size - pos, 0);
# else
ret = read(urandom_fd, (char *) buf + pos, size - pos);
# endif
if (unlikely(ret <= 0)) {
if (ret == 0)
i_fatal("EOF when reading from "DEV_URANDOM_PATH);
i_fatal("read("DEV_URANDOM_PATH") failed: EOF");
else if (errno != EINTR)
# if defined(USE_RANDOM_DEV)
i_fatal("read("DEV_URANDOM_PATH") failed: %m");
# elif defined(USE_GETRANDOM)
i_fatal("getrandom() failed: %m");
# endif
} else {
pos += ret;
}
}
#endif /* defined(USE_ARC4RANDOM) */
}

void random_init(void)
Expand All @@ -36,49 +64,27 @@ void random_init(void)

if (init_refcount++ > 0)
return;

#if defined(USE_RANDOM_DEV)
urandom_fd = open(DEV_URANDOM_PATH, O_RDONLY);
if (urandom_fd == -1) {
if (errno == ENOENT) {
i_fatal(DEV_URANDOM_PATH" doesn't exist, "
i_fatal("open("DEV_URANDOM_PATH") failed: doesn't exist,"
"currently we require it");
} else {
i_fatal("Can't open "DEV_URANDOM_PATH": %m");
i_fatal("open("DEV_URANDOM_PATH") failed: %m");
}
}

fd_close_on_exec(urandom_fd, TRUE);
#endif
random_fill(&seed, sizeof(seed));
srand(seed);

fd_close_on_exec(urandom_fd, TRUE);
}

void random_deinit(void)
{
if (--init_refcount > 0)
return;

#if defined(USE_RANDOM_DEV)
i_close_fd(&urandom_fd);
}

#ifdef HAVE_ARC4RANDOM
#ifdef HAVE_LIBBSD
#include <bsd/stdlib.h>
#endif

void random_fill_weak(void *buf, size_t size)
{
arc4random_buf(buf, size);
}

#else

void random_fill_weak(void *buf, size_t size)
{
unsigned char *cbuf = buf;

for (; size > 0; size--)
*cbuf++ = (unsigned char)rand();
}

#endif
10 changes: 4 additions & 6 deletions src/lib/randgen.h
@@ -1,14 +1,12 @@
#ifndef RANDGEN_H
#define RANDGEN_H

/* Fill given buffer with semi-strong randomness, usually from /dev/urandom. */
/* Fill given buffer with semi-strong randomness */
void random_fill(void *buf, size_t size);
/* Fill given buffer with weak randomness, ie. with rand(). This is better if
no real randomness is required, as reading from /dev/urandom usually also
consumes /dev/random entropy, which may disturb other processes. */
void random_fill_weak(void *buf, size_t size);
#define random_fill_weak(buf,size) random_fill((buf), (size))

/* may be called multiple times */
/* may be called multiple times,
and are called by default in lib_init */
void random_init(void);
void random_deinit(void);

Expand Down

0 comments on commit 8045f6e

Please sign in to comment.