1
mirror of https://github.com/jedisct1/libsodium.git synced 2024-12-24 12:36:01 -07:00

Use getentropy(2) if available, cleanup salsa20/randombytes by the way

This commit is contained in:
Frank Denis 2019-03-17 18:55:40 +01:00
parent 9c6ee44d93
commit 0ea9a8f0e9
4 changed files with 180 additions and 122 deletions

View File

@ -539,7 +539,7 @@ AC_SUBST(CFLAGS_AESNI)
AC_SUBST(CFLAGS_PCLMUL) AC_SUBST(CFLAGS_PCLMUL)
AC_SUBST(CFLAGS_RDRAND) AC_SUBST(CFLAGS_RDRAND)
AC_CHECK_HEADERS([sys/mman.h intrin.h]) AC_CHECK_HEADERS([sys/mman.h sys/random.h intrin.h])
AC_MSG_CHECKING([if _xgetbv() is available]) AC_MSG_CHECKING([if _xgetbv() is available])
AC_LINK_IFELSE( AC_LINK_IFELSE(
@ -779,11 +779,11 @@ dnl Checks for functions and headers
AC_FUNC_ALLOCA AC_FUNC_ALLOCA
AS_IF([test "x$EMSCRIPTEN" = "x"],[ AS_IF([test "x$EMSCRIPTEN" = "x"],[
AC_CHECK_FUNCS([arc4random arc4random_buf]) AC_CHECK_FUNCS([arc4random arc4random_buf getentropy])
AC_CHECK_FUNCS([mmap mlock madvise mprotect]) AC_CHECK_FUNCS([mmap mlock madvise mprotect])
]) ])
AC_CHECK_FUNCS([posix_memalign getpid getentropy memset_s explicit_bzero AC_CHECK_FUNCS([posix_memalign getpid nanosleep])
explicit_memset nanosleep]) AC_CHECK_FUNCS([memset_s explicit_bzero explicit_memset])
AC_SUBST([LIBTOOL_EXTRA_FLAGS]) AC_SUBST([LIBTOOL_EXTRA_FLAGS])

View File

@ -13,9 +13,10 @@
#include "core.h" #include "core.h"
#include "crypto_stream_chacha20.h" #include "crypto_stream_chacha20.h"
#include "randombytes.h" #include "randombytes.h"
#ifndef RANDOMBYTES_CUSTOM_IMPLEMENTATION
# ifdef RANDOMBYTES_DEFAULT_IMPLEMENTATION # ifdef RANDOMBYTES_DEFAULT_IMPLEMENTATION
# include "randombytes_default.h" # include "randombytes_salsa20.h"
#else # endif
# include "randombytes_sysrandom.h" # include "randombytes_sysrandom.h"
#endif #endif
#include "private/common.h" #include "private/common.h"

View File

@ -31,10 +31,12 @@
#elif defined(__FreeBSD__) #elif defined(__FreeBSD__)
# include <sys/param.h> # include <sys/param.h>
# if defined(__FreeBSD_version) && __FreeBSD_version >= 1200000 # if defined(__FreeBSD_version) && __FreeBSD_version >= 1200000
# include <sys/random.h>
# define HAVE_LINUX_COMPATIBLE_GETRANDOM # define HAVE_LINUX_COMPATIBLE_GETRANDOM
# endif # endif
#endif #endif
#ifdef HAVE_SYS_RANDOM_H
# include <sys/random.h>
#endif
#if !defined(NO_BLOCKING_RANDOM_POLL) && defined(__linux__) #if !defined(NO_BLOCKING_RANDOM_POLL) && defined(__linux__)
# define BLOCK_ON_DEV_RANDOM # define BLOCK_ON_DEV_RANDOM
#endif #endif
@ -75,6 +77,9 @@ BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength);
#if defined(__OpenBSD__) || defined(__CloudABI__) #if defined(__OpenBSD__) || defined(__CloudABI__)
# define HAVE_SAFE_ARC4RANDOM 1 # define HAVE_SAFE_ARC4RANDOM 1
#endif #endif
#if defined(__CloudABI__) || defined(__wasm__)
# define NONEXISTENT_DEV_RANDOM 1
#endif
#ifndef SSIZE_MAX #ifndef SSIZE_MAX
# define SSIZE_MAX (SIZE_MAX / 2 - 1) # define SSIZE_MAX (SIZE_MAX / 2 - 1)
@ -98,6 +103,7 @@ BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength);
typedef struct Salsa20RandomGlobal_ { typedef struct Salsa20RandomGlobal_ {
int initialized; int initialized;
int random_data_source_fd; int random_data_source_fd;
int getentropy_available;
int getrandom_available; int getrandom_available;
int rdrand_available; int rdrand_available;
#ifdef HAVE_GETPID #ifdef HAVE_GETPID
@ -152,7 +158,7 @@ sodium_hrtime(void)
} }
return ((uint64_t) tv.tv_sec) * 1000000U + (uint64_t) tv.tv_usec; return ((uint64_t) tv.tv_sec) * 1000000U + (uint64_t) tv.tv_usec;
} }
#endif #endif /* _WIN32 */
/* /*
* Initialize the entropy source * Initialize the entropy source
@ -168,6 +174,119 @@ randombytes_salsa20_random_init(void)
#else /* _WIN32 */ #else /* _WIN32 */
# ifdef HAVE_GETENTROPY
static int
_randombytes_getentropy(void * const buf, const size_t size)
{
int readnb;
assert(size <= 256U);
do {
readnb = getentropy(buf, size);
} while (readnb < 0 && (errno == EINTR || errno == EAGAIN));
return (readnb == (int) size) - 1;
}
static int
randombytes_getentropy(void * const buf_, size_t size)
{
unsigned char *buf = (unsigned char *) buf_;
size_t chunk_size = 256U;
do {
if (size < chunk_size) {
chunk_size = size;
assert(chunk_size > (size_t) 0U);
}
if (_randombytes_getentropy(buf, chunk_size) != 0) {
return -1;
}
size -= chunk_size;
buf += chunk_size;
} while (size > (size_t) 0U);
return 0;
}
# elif defined(HAVE_LINUX_COMPATIBLE_GETRANDOM)
static int
_randombytes_linux_getrandom(void * const buf, const size_t size)
{
int readnb;
assert(size <= 256U);
do {
readnb = getrandom(buf, size, 0);
} while (readnb < 0 && (errno == EINTR || errno == EAGAIN));
return (readnb == (int) size) - 1;
}
static int
randombytes_linux_getrandom(void * const buf_, size_t size)
{
unsigned char *buf = (unsigned char *) buf_;
size_t chunk_size = 256U;
do {
if (size < chunk_size) {
chunk_size = size;
assert(chunk_size > (size_t) 0U);
}
if (_randombytes_linux_getrandom(buf, chunk_size) != 0) {
return -1;
}
size -= chunk_size;
buf += chunk_size;
} while (size > (size_t) 0U);
return 0;
}
# endif
# ifndef NONEXISTENT_DEV_RANDOM
static int
randombytes_salsa20_random_random_dev_open(void)
{
/* LCOV_EXCL_START */
struct stat st;
static const char *devices[] = {
# ifndef USE_BLOCKING_RANDOM
"/dev/urandom",
# endif
"/dev/random", NULL
};
const char **device = devices;
int fd;
# ifdef BLOCK_ON_DEV_RANDOM
if (randombytes_block_on_dev_random() != 0) {
return -1;
}
# endif
do {
fd = open(*device, O_RDONLY);
if (fd != -1) {
if (fstat(fd, &st) == 0 && (S_ISNAM(st.st_mode) || S_ISCHR(st.st_mode))) {
# if defined(F_SETFD) && defined(FD_CLOEXEC)
(void) fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
# endif
return fd;
}
(void) close(fd);
} else if (errno == EINTR) {
continue;
}
device++;
} while (*device != NULL);
errno = EIO;
return -1;
/* LCOV_EXCL_STOP */
}
static ssize_t static ssize_t
safe_read(const int fd, void * const buf_, size_t size) safe_read(const int fd, void * const buf_, size_t size)
{ {
@ -219,83 +338,7 @@ randombytes_block_on_dev_random(void)
} }
# endif # endif
# ifndef HAVE_SAFE_ARC4RANDOM # endif /* !NONEXISTENT_DEV_RANDOM */
static int
randombytes_salsa20_random_random_dev_open(void)
{
/* LCOV_EXCL_START */
struct stat st;
static const char *devices[] = {
# ifndef USE_BLOCKING_RANDOM
"/dev/urandom",
# endif
"/dev/random", NULL
};
const char **device = devices;
int fd;
# ifdef BLOCK_ON_DEV_RANDOM
if (randombytes_block_on_dev_random() != 0) {
return -1;
}
# endif
do {
fd = open(*device, O_RDONLY);
if (fd != -1) {
if (fstat(fd, &st) == 0 && (S_ISNAM(st.st_mode) || S_ISCHR(st.st_mode))) {
# if defined(F_SETFD) && defined(FD_CLOEXEC)
(void) fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
# endif
return fd;
}
(void) close(fd);
} else if (errno == EINTR) {
continue;
}
device++;
} while (*device != NULL);
errno = EIO;
return -1;
/* LCOV_EXCL_STOP */
}
# endif
# ifdef HAVE_LINUX_COMPATIBLE_GETRANDOM
static int
_randombytes_linux_getrandom(void * const buf, const size_t size)
{
int readnb;
assert(size <= 256U);
do {
readnb = getrandom(buf, size, 0);
} while (readnb < 0 && (errno == EINTR || errno == EAGAIN));
return (readnb == (int) size) - 1;
}
static int
randombytes_linux_getrandom(void * const buf_, size_t size)
{
unsigned char *buf = (unsigned char *) buf_;
size_t chunk_size = 256U;
do {
if (size < chunk_size) {
chunk_size = size;
assert(chunk_size > (size_t) 0U);
}
if (_randombytes_linux_getrandom(buf, chunk_size) != 0) {
return -1;
}
size -= chunk_size;
buf += chunk_size;
} while (size > (size_t) 0U);
return 0;
}
# endif
static void static void
randombytes_salsa20_random_init(void) randombytes_salsa20_random_init(void)
@ -303,12 +346,20 @@ randombytes_salsa20_random_init(void)
const int errno_save = errno; const int errno_save = errno;
global.rdrand_available = sodium_runtime_has_rdrand(); global.rdrand_available = sodium_runtime_has_rdrand();
global.getentropy_available = 0;
global.getrandom_available = 0;
# ifdef HAVE_SAFE_ARC4RANDOM # ifdef HAVE_GETENTROPY
{
unsigned char fodder[16];
if (randombytes_getentropy(fodder, sizeof fodder) == 0) {
global.getentropy_available = 1;
errno = errno_save; errno = errno_save;
# else return;
}
# ifdef HAVE_LINUX_COMPATIBLE_GETRANDOM }
# elif defined(HAVE_LINUX_COMPATIBLE_GETRANDOM)
{ {
unsigned char fodder[16]; unsigned char fodder[16];
@ -317,16 +368,18 @@ randombytes_salsa20_random_init(void)
errno = errno_save; errno = errno_save;
return; return;
} }
global.getrandom_available = 0;
} }
# endif /* HAVE_LINUX_COMPATIBLE_GETRANDOM */ # elif !defined(NONEXISTENT_DEV_RANDOM)
assert((global.getentropy_available | global.getrandom_available) == 0);
if ((global.random_data_source_fd = if ((global.random_data_source_fd =
randombytes_salsa20_random_random_dev_open()) == -1) { randombytes_salsa20_random_random_dev_open()) == -1) {
sodium_misuse(); /* LCOV_EXCL_LINE */ sodium_misuse(); /* LCOV_EXCL_LINE */
} }
# elif !defined(HAVE_SAFE_ARC4RANDOM)
sodium_misuse();
# endif
errno = errno_save; errno = errno_save;
# endif /* HAVE_SAFE_ARC4RANDOM */
} }
#endif /* _WIN32 */ #endif /* _WIN32 */
@ -352,18 +405,20 @@ randombytes_salsa20_random_stir(void)
#ifndef _WIN32 #ifndef _WIN32
# ifdef HAVE_SAFE_ARC4RANDOM # ifdef HAVE_GETENTROPY
arc4random_buf(stream.key, sizeof stream.key); if (global.getentropy_available != 0) {
if (randombytes_getentropy(stream.key, sizeof stream.key) != 0) {
sodium_misuse(); /* LCOV_EXCL_LINE */
}
}
# elif defined(HAVE_LINUX_COMPATIBLE_GETRANDOM) # elif defined(HAVE_LINUX_COMPATIBLE_GETRANDOM)
if (global.getrandom_available != 0) { if (global.getrandom_available != 0) {
if (randombytes_linux_getrandom(stream.key, sizeof stream.key) != 0) { if (randombytes_getrandom(stream.key, sizeof stream.key) != 0) {
sodium_misuse(); /* LCOV_EXCL_LINE */ sodium_misuse(); /* LCOV_EXCL_LINE */
} }
} else if (global.random_data_source_fd == -1 ||
safe_read(global.random_data_source_fd, stream.key,
sizeof stream.key) != (ssize_t) sizeof stream.key) {
sodium_misuse(); /* LCOV_EXCL_LINE */
} }
# elif !defined(NONEXISTENT_DEV_RANDOM) && defined(HAVE_SAFE_ARC4RANDOM)
arc4random_buf(stream.key, sizeof stream.key);
# else # else
if (global.random_data_source_fd == -1 || if (global.random_data_source_fd == -1 ||
safe_read(global.random_data_source_fd, stream.key, safe_read(global.random_data_source_fd, stream.key,
@ -425,6 +480,17 @@ randombytes_salsa20_random_close(void)
{ {
int ret = -1; int ret = -1;
# ifdef HAVE_GETENTROPY
if (global.getentropy_available != 0) {
ret = 0;
}
# elif defined(HAVE_LINUX_COMPATIBLE_GETRANDOM)
if (global.getrandom_available != 0) {
ret = 0;
}
# elif !defined(NONEXISTENT_DEV_RANDOM) && defined(HAVE_SAFE_ARC4RANDOM)
ret = 0;
# else
if (global.random_data_source_fd != -1 && if (global.random_data_source_fd != -1 &&
close(global.random_data_source_fd) == 0) { close(global.random_data_source_fd) == 0) {
global.random_data_source_fd = -1; global.random_data_source_fd = -1;
@ -434,15 +500,6 @@ randombytes_salsa20_random_close(void)
# endif # endif
ret = 0; ret = 0;
} }
# ifdef HAVE_SAFE_ARC4RANDOM
ret = 0;
# endif
# ifdef HAVE_LINUX_COMPATIBLE_GETRANDOM
if (global.getrandom_available != 0) {
ret = 0;
}
# endif # endif
sodium_memzero(&stream, sizeof stream); sodium_memzero(&stream, sizeof stream);

View File

@ -105,7 +105,7 @@ randombytes_sysrandom_close(void)
return 0; return 0;
} }
#else /* __OpenBSD__ */ #else /* HAVE_SAFE_ARC4RANDOM */
typedef struct SysRandom_ { typedef struct SysRandom_ {
int random_data_source_fd; int random_data_source_fd;