From 3505db86a52bb85c7cf95d14bae557094d930657 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Mon, 21 Jan 2013 14:36:26 -0800 Subject: [PATCH] Add randombytes_sysrandom and use that as the default randombytes impl. --- src/libsodium/Makefile.am | 2 + .../sodium/randombytes_salsa20_random.h | 4 +- .../include/sodium/randombytes_sysrandom.h | 24 +++ src/libsodium/randombytes/randombytes.c | 14 +- .../randombytes/randombytes_sysrandom.c | 202 ++++++++++++++++++ 5 files changed, 237 insertions(+), 9 deletions(-) create mode 100644 src/libsodium/include/sodium/randombytes_sysrandom.h create mode 100644 src/libsodium/randombytes/randombytes_sysrandom.c diff --git a/src/libsodium/Makefile.am b/src/libsodium/Makefile.am index 102a617e..4da22bd1 100644 --- a/src/libsodium/Makefile.am +++ b/src/libsodium/Makefile.am @@ -75,6 +75,8 @@ libsodium_la_SOURCES = \ randombytes/randombytes.c \ randombytes/randombytes_salsa20_random.c \ randombytes/randombytes_salsa20_random.h \ + randombytes/randombytes_sysrandom.c \ + randombytes/randombytes_sysrandom.h \ version.c EXTRA_DIST = \ diff --git a/src/libsodium/include/sodium/randombytes_salsa20_random.h b/src/libsodium/include/sodium/randombytes_salsa20_random.h index 29e49275..3352655a 100644 --- a/src/libsodium/include/sodium/randombytes_salsa20_random.h +++ b/src/libsodium/include/sodium/randombytes_salsa20_random.h @@ -1,6 +1,6 @@ -#ifndef __SALSA20_RANDOM_H__ -#define __SALSA20_RANDOM_H__ 1 +#ifndef randombytes_salsa20_random_H +#define randombytes_salsa20_random_H #include #include diff --git a/src/libsodium/include/sodium/randombytes_sysrandom.h b/src/libsodium/include/sodium/randombytes_sysrandom.h new file mode 100644 index 00000000..de8c2e08 --- /dev/null +++ b/src/libsodium/include/sodium/randombytes_sysrandom.h @@ -0,0 +1,24 @@ + +#ifndef randombytes_sysrandom_H +#define randombytes_sysrandom_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +const char *sysrandom_implementation_name(void); + +uint32_t sysrandom(void); +void sysrandom_stir(void); +uint32_t sysrandom_uniform(const uint32_t upper_bound); +void sysrandom_buf(void * const buf, const size_t size); +int sysrandom_close(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libsodium/randombytes/randombytes.c b/src/libsodium/randombytes/randombytes.c index c681c7df..942c54bd 100644 --- a/src/libsodium/randombytes/randombytes.c +++ b/src/libsodium/randombytes/randombytes.c @@ -5,15 +5,15 @@ #include #include "randombytes.h" -#include "randombytes_salsa20_random.h" +#include "randombytes_sysrandom.h" static randombytes_implementation implementation = { - .randombytes_implementation_name = salsa20_random_implementation_name, - .randombytes_random = salsa20_random, - .randombytes_stir = salsa20_random_stir, - .randombytes_uniform = salsa20_random_uniform, - .randombytes_buf = salsa20_random_buf, - .randombytes_close = salsa20_random_close + .randombytes_implementation_name = sysrandom_implementation_name, + .randombytes_random = sysrandom, + .randombytes_stir = sysrandom_stir, + .randombytes_uniform = sysrandom_uniform, + .randombytes_buf = sysrandom_buf, + .randombytes_close = sysrandom_close }; int diff --git a/src/libsodium/randombytes/randombytes_sysrandom.c b/src/libsodium/randombytes/randombytes_sysrandom.c new file mode 100644 index 00000000..7f5e60a9 --- /dev/null +++ b/src/libsodium/randombytes/randombytes_sysrandom.c @@ -0,0 +1,202 @@ + +#include +#include + +#include +#include +#include +#include +#ifndef _WIN32 +# include +#endif +#include +#include +#include +#include + +#include "randombytes_sysrandom.h" + +#ifdef _WIN32 +# include +# include +#endif + +#define COMPILER_ASSERT(X) (void) sizeof(char[(X) ? 1 : -1]) + +typedef struct SysRandom_ { +#ifdef _WIN32 + HCRYPTPROV hcrypt_prov; +#endif + int random_data_source_fd; + _Bool initialized; +} SysRandom; + +static SysRandom stream = { + .random_data_source_fd = -1, + .initialized = 0 +}; + +#ifndef _WIN32 +static ssize_t +safe_read(const int fd, void * const buf_, size_t count) +{ + unsigned char *buf = (unsigned char *) buf_; + ssize_t readnb; + + do { + while ((readnb = read(fd, buf, count)) < (ssize_t) 0 && + errno == EINTR); + if (readnb < (ssize_t) 0) { + return readnb; + } + if (readnb == (ssize_t) 0) { + break; + } + count -= (size_t) readnb; + buf += readnb; + } while (count > (ssize_t) 0); + + return (ssize_t) (buf - (unsigned char *) buf_); +} +#endif + +#ifndef _WIN32 +static int +sysrandom_random_dev_open(void) +{ + static const char * const devices[] = { +# ifndef USE_BLOCKING_RANDOM + "/dev/arandom", "/dev/urandom", +# endif + "/dev/random", NULL + }; + const char * const *device = devices; + + do { + if (access(*device, F_OK | R_OK) == 0) { + return open(*device, O_RDONLY); + } + device++; + } while (*device != NULL); + + return -1; +} + +static void +sysrandom_init(void) +{ + if ((stream.random_data_source_fd = + sysrandom_random_dev_open()) == -1) { + abort(); + } +} + +#else /* _WIN32 */ + +static void +sysrandom_init(void) +{ + if (! CryptAcquireContext(&stream.hcrypt_prov, NULL, NULL, + PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + abort(); + } +} +#endif + +void +sysrandom_stir(void) +{ + if (stream.initialized == 0) { + sysrandom_init(); + stream.initialized = 1; + } +} + +static void +sysrandom_stir_if_needed(void) +{ + if (stream.initialized == 0) { + sysrandom_stir(); + } +} + +int +sysrandom_close(void) +{ + int ret = -1; + +#ifndef _WIN32 + if (stream.random_data_source_fd != -1 && + close(stream.random_data_source_fd) == 0) { + stream.random_data_source_fd = -1; + stream.initialized = 0; + ret = 0; + } +#else /* _WIN32 */ + if (stream.initialized != 0 && + CryptReleaseContext(stream.hcrypt_prov, 0)) { + stream.initialized = 0; + ret = 0; + } +#endif + return ret; +} + +uint32_t +sysrandom(void) +{ + uint32_t r; + + sysrandom_stir_if_needed(); + sysrandom_buf(&r, sizeof r); + + return r; +} + +void +sysrandom_buf(void * const buf, const size_t size) +{ + sysrandom_stir_if_needed(); +#ifdef ULONG_LONG_MAX + assert(size <= ULONG_LONG_MAX); +#endif +#ifndef _WIN32 + if (safe_read(stream.random_data_source_fd, buf, size) != (ssize_t) size) { + abort(); + } +#else + if (! CryptGenRandom(stream.hcrypt_prov, buf, size)) { + abort(); + } +#endif +} + +/* + * sysrandom_uniform() derives from OpenBSD's arc4random_uniform() + * Copyright (c) 2008, Damien Miller + */ + +uint32_t +sysrandom_uniform(const uint32_t upper_bound) +{ + uint32_t min; + uint32_t r; + + if (upper_bound < 2) { + return 0; + } + min = (uint32_t) (-upper_bound % upper_bound); + for (;;) { + r = sysrandom(); + if (r >= min) { + break; + } + } + return r % upper_bound; +} + +const char * +sysrandom_implementation_name(void) +{ + return "sysrandom"; +}