From dde2e8086cce808a8ff4843a953670f07754db01 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Mon, 21 Jan 2013 12:23:57 -0800 Subject: [PATCH] Use salsa20_random() for randombytes, install libsodium-randombytes DLL. --- configure.ac | 2 +- src/libsodium/Makefile.am | 18 +- src/libsodium/include/sodium/randombytes.h | 7 +- src/libsodium/randombytes/devurandom.c | 46 --- src/libsodium/randombytes/devurandom.h | 24 -- src/libsodium/randombytes/randombytes.c | 15 + src/libsodium/randombytes/salsa20_random.c | 308 +++++++++++++++++++++ src/libsodium/randombytes/salsa20_random.h | 14 + 8 files changed, 352 insertions(+), 82 deletions(-) delete mode 100644 src/libsodium/randombytes/devurandom.c delete mode 100644 src/libsodium/randombytes/devurandom.h create mode 100644 src/libsodium/randombytes/randombytes.c create mode 100644 src/libsodium/randombytes/salsa20_random.c create mode 100644 src/libsodium/randombytes/salsa20_random.h diff --git a/configure.ac b/configure.ac index 7deea474..89c5a83b 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.61]) AC_INIT([libsodium],[0.0.1],[https://github.com/jedisct1/libsodium]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_AUX_DIR([libltdl/config]) -AC_CONFIG_SRCDIR([src/libsodium/randombytes/devurandom.c]) +AC_CONFIG_SRCDIR([src/libsodium/version.c]) AC_CANONICAL_HOST AM_INIT_AUTOMAKE([1.11 dist-bzip2 tar-ustar]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) diff --git a/src/libsodium/Makefile.am b/src/libsodium/Makefile.am index 7dab605d..66dc703e 100644 --- a/src/libsodium/Makefile.am +++ b/src/libsodium/Makefile.am @@ -1,13 +1,12 @@ lib_LTLIBRARIES = \ - libsodium.la - -noinst_LTLIBRARIES = \ + libsodium.la \ libsodium-randombytes.la libsodium_randombytes_la_SOURCES = \ - randombytes/devurandom.c \ - randombytes/devurandom.h + randombytes/randombytes.c \ + randombytes/salsa20_random.c \ + randombytes/salsa20_random.h libsodium_la_SOURCES = \ crypto_core/hsalsa20/ref2/core_hsalsa20.c \ @@ -93,5 +92,14 @@ libsodium_la_CPPFLAGS = \ $(LTDLINCL) \ -I$(top_srcdir)/src/libsodium/include/sodium +libsodium_randombytes_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + -export-dynamic \ + -version-info $(SODIUM_LIBRARY_VERSION) + +libsodium_randombytes_la_CPPFLAGS = \ + $(LTDLINCL) \ + -I$(top_srcdir)/src/libsodium/include/sodium + SUBDIRS = \ include diff --git a/src/libsodium/include/sodium/randombytes.h b/src/libsodium/include/sodium/randombytes.h index 2e0caf8a..eee22bed 100644 --- a/src/libsodium/include/sodium/randombytes.h +++ b/src/libsodium/include/sodium/randombytes.h @@ -1,8 +1,3 @@ -/* -randombytes/devurandom.h version 20080713 -D. J. Bernstein -Public domain. -*/ #ifndef randombytes_devurandom_H #define randombytes_devurandom_H @@ -18,7 +13,7 @@ extern void randombytes(unsigned char *,unsigned long long); #endif #ifndef randombytes_implementation -#define randombytes_implementation "devurandom" +#define randombytes_implementation "salsa20_random" #endif #endif diff --git a/src/libsodium/randombytes/devurandom.c b/src/libsodium/randombytes/devurandom.c deleted file mode 100644 index d8b24db5..00000000 --- a/src/libsodium/randombytes/devurandom.c +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include -#include -#include -#ifdef _WIN32 -# include -#endif - -/* it's really stupid that there isn't a syscall for this */ -/* -> Y U NO USE OPENBSD? */ - -static int fd = -1; - -void randombytes(unsigned char *x,unsigned long long xlen) -{ - int i; - - if (fd == -1) { - for (;;) { - fd = open("/dev/urandom",O_RDONLY); - if (fd != -1) break; -#ifdef _WIN32 - Sleep(1000); -#else - sleep(1); -#endif - } - } - - while (xlen > 0) { - if (xlen < 1048576) i = xlen; else i = 1048576; - - i = read(fd,x,i); - if (i < 1) { -#ifdef _WIN32 - Sleep(1000); -#else - sleep(1); -#endif - continue; - } - - x += i; - xlen -= i; - } -} diff --git a/src/libsodium/randombytes/devurandom.h b/src/libsodium/randombytes/devurandom.h deleted file mode 100644 index 2e0caf8a..00000000 --- a/src/libsodium/randombytes/devurandom.h +++ /dev/null @@ -1,24 +0,0 @@ -/* -randombytes/devurandom.h version 20080713 -D. J. Bernstein -Public domain. -*/ - -#ifndef randombytes_devurandom_H -#define randombytes_devurandom_H - -#ifdef __cplusplus -extern "C" { -#endif - -extern void randombytes(unsigned char *,unsigned long long); - -#ifdef __cplusplus -} -#endif - -#ifndef randombytes_implementation -#define randombytes_implementation "devurandom" -#endif - -#endif diff --git a/src/libsodium/randombytes/randombytes.c b/src/libsodium/randombytes/randombytes.c new file mode 100644 index 00000000..a5bba049 --- /dev/null +++ b/src/libsodium/randombytes/randombytes.c @@ -0,0 +1,15 @@ + +#include + +#include +#include + +#include "randombytes.h" +#include "salsa20_random.h" + +void +randombytes(unsigned char * const buf, const unsigned long long buf_len) +{ + assert(buf_len <= SIZE_MAX); + salsa20_random_buf(buf, buf_len); +} diff --git a/src/libsodium/randombytes/salsa20_random.c b/src/libsodium/randombytes/salsa20_random.c new file mode 100644 index 00000000..4df57663 --- /dev/null +++ b/src/libsodium/randombytes/salsa20_random.c @@ -0,0 +1,308 @@ + +#include +#include + +#include +#include +#include +#include +#ifndef _WIN32 +# include +#endif +#include +#include +#include +#include + +#include "crypto_core_salsa20.h" +#include "crypto_hash_sha256.h" +#include "crypto_stream_salsa20.h" +#include "salsa20_random.h" + +#ifdef _WIN32 +# include +# include +#endif + +#define SALSA20_RANDOM_BLOCK_SIZE crypto_core_salsa20_OUTPUTBYTES +#define SHA256_BLOCK_SIZE 64U +#define SHA256_MIN_PAD_SIZE (1U + 8U) +#define COMPILER_ASSERT(X) (void) sizeof(char[(X) ? 1 : -1]) + +typedef struct Salsa20Random_ { + unsigned char key[crypto_stream_salsa20_KEYBYTES]; + unsigned char rnd32[SALSA20_RANDOM_BLOCK_SIZE]; + uint64_t nonce; + size_t rnd32_outleft; + pid_t pid; +#ifdef _WIN32 + HCRYPTPROV hcrypt_prov; +#endif + int random_data_source_fd; + _Bool initialized; +} Salsa20Random; + +static Salsa20Random stream = { + .random_data_source_fd = -1, + .rnd32_outleft = (size_t) 0U, + .initialized = 0 +}; + +static void +sodium_memzero(void * const pnt, const size_t size) +{ +#ifdef _WIN32 + SecureZeroMemory(pnt, size); +#else + volatile unsigned char *pnt_ = (volatile unsigned char *) pnt; + size_t i = (size_t) 0U; + + while (i < size) { + pnt_[i++] = 0U; + } +#endif +} + +static uint64_t +sodium_hrtime(void) +{ + struct timeval tv; + uint64_t ts = (uint64_t) 0U; + int ret; + +#ifdef _WIN32 + struct _timeb tb; + + _ftime(&tb); + tv.tv_sec = (long) tb.time; + tv.tv_usec = ((int) tb.millitm) * 1000; + ret = 0; +#else + ret = gettimeofday(&tv, NULL); +#endif + assert(ret == 0); + if (ret == 0) { + ts = (uint64_t) tv.tv_sec * 1000000U + (uint64_t) tv.tv_usec; + } + return ts; +} + +#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 +salsa20_random_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 +salsa20_random_init(void) +{ + stream.nonce = sodium_hrtime(); + assert(stream.nonce != (uint64_t) 0U); + + if ((stream.random_data_source_fd = + salsa20_random_random_dev_open()) == -1) { + abort(); + } +} + +#else /* _WIN32 */ + +static void +salsa20_random_init(void) +{ + stream.nonce = sodium_hrtime(); + assert(stream.nonce != (uint64_t) 0U); + + if (! CryptAcquireContext(&stream.hcrypt_prov, NULL, NULL, + PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + abort(); + } +} +#endif + +void +salsa20_random_stir(void) +{ + unsigned char m0[3U * SHA256_BLOCK_SIZE - SHA256_MIN_PAD_SIZE]; + unsigned char m1[SHA256_BLOCK_SIZE + crypto_hash_sha256_BYTES]; + unsigned char *k0 = m0 + SHA256_BLOCK_SIZE; + unsigned char *k1 = m1 + SHA256_BLOCK_SIZE; + size_t i; + size_t sizeof_k0 = sizeof m0 - SHA256_BLOCK_SIZE; + + memset(stream.rnd32, 0, sizeof stream.rnd32); + stream.rnd32_outleft = (size_t) 0U; + if (stream.initialized == 0) { + salsa20_random_init(); + stream.initialized = 1; + } + memset(m0, 0x69, SHA256_BLOCK_SIZE); + memset(m1, 0x42, SHA256_BLOCK_SIZE); +#ifndef _WIN32 + if (safe_read(stream.random_data_source_fd, k0, + sizeof_k0) != (ssize_t) sizeof_k0) { + abort(); + } +#else /* _WIN32 */ + if (! CryptGenRandom(stream.hcrypt_prov, sizeof_k0, k0)) { + abort(); + } +#endif + COMPILER_ASSERT(sizeof m0 >= 2U * SHA256_BLOCK_SIZE); + crypto_hash_sha256(k1, m0, sizeof m0); + COMPILER_ASSERT(sizeof m1 >= SHA256_BLOCK_SIZE + crypto_hash_sha256_BYTES); + crypto_hash_sha256(stream.key, m1, sizeof m1); + sodium_memzero(m1, sizeof m1); + COMPILER_ASSERT(sizeof stream.key == crypto_hash_sha256_BYTES); + assert(sizeof stream.key <= sizeof_k0); + for (i = (size_t) 0U; i < sizeof stream.key; i++) { + stream.key[i] ^= k0[i]; + } + sodium_memzero(m0, sizeof m0); +} + +static void +salsa20_random_stir_if_needed(void) +{ + const pid_t pid = getpid(); + + if (stream.initialized == 0 || stream.pid != pid) { + stream.pid = pid; + salsa20_random_stir(); + } +} + +static uint32_t +salsa20_random_getword(void) +{ + uint32_t val; + int ret; + + COMPILER_ASSERT(sizeof stream.rnd32 >= sizeof val); + COMPILER_ASSERT(sizeof stream.rnd32 % sizeof val == (size_t) 0U); + if (stream.rnd32_outleft <= (size_t) 0U) { + COMPILER_ASSERT(sizeof stream.nonce == crypto_stream_salsa20_NONCEBYTES); + ret = crypto_stream_salsa20((unsigned char *) stream.rnd32, + (unsigned long long) sizeof stream.rnd32, + (unsigned char *) &stream.nonce, + stream.key); + assert(ret == 0); + stream.nonce++; + stream.rnd32_outleft = sizeof stream.rnd32; + } + stream.rnd32_outleft -= sizeof val; + memcpy(&val, &stream.rnd32[stream.rnd32_outleft], sizeof val); + + return val; +} + +int +salsa20_random_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 +salsa20_random(void) +{ + salsa20_random_stir_if_needed(); + + return salsa20_random_getword(); +} + +void +salsa20_random_buf(void * const buf, const size_t size) +{ + int ret; + + salsa20_random_stir_if_needed(); + COMPILER_ASSERT(sizeof stream.nonce == crypto_stream_salsa20_NONCEBYTES); +#ifdef ULONG_LONG_MAX + assert(size <= ULONG_LONG_MAX); +#endif + ret = crypto_stream_salsa20(buf, (unsigned long long) size, + (unsigned char *) &stream.nonce, + stream.key); + assert(ret == 0); + stream.nonce++; +} + +/* + * salsa20_random_uniform() derives from OpenBSD's arc4random_uniform() + * Copyright (c) 2008, Damien Miller + */ + +uint32_t +salsa20_random_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 = salsa20_random(); + if (r >= min) { + break; + } + } + return r % upper_bound; +} diff --git a/src/libsodium/randombytes/salsa20_random.h b/src/libsodium/randombytes/salsa20_random.h new file mode 100644 index 00000000..2df9c2e9 --- /dev/null +++ b/src/libsodium/randombytes/salsa20_random.h @@ -0,0 +1,14 @@ + +#ifndef __SALSA20_RANDOM_H__ +#define __SALSA20_RANDOM_H__ 1 + +#include +#include + +uint32_t salsa20_random(void); +void salsa20_random_stir(void); +uint32_t salsa20_random_uniform(const uint32_t upper_bound); +void salsa20_random_buf(void * const buf, const size_t size); +int salsa20_random_close(void); + +#endif