diff --git a/src/libsodium/randombytes/salsa20/randombytes_salsa20_random.c b/src/libsodium/randombytes/salsa20/randombytes_salsa20_random.c index 4e51381f..dba91e7c 100644 --- a/src/libsodium/randombytes/salsa20/randombytes_salsa20_random.c +++ b/src/libsodium/randombytes/salsa20/randombytes_salsa20_random.c @@ -4,6 +4,9 @@ # include # include #endif +#ifdef __linux__ +# include +#endif #include #include @@ -49,12 +52,14 @@ typedef struct Salsa20Random_ { #endif int random_data_source_fd; int initialized; + int getrandom_available; } Salsa20Random; static Salsa20Random stream = { SODIUM_C99(.random_data_source_fd =) -1, SODIUM_C99(.rnd32_outleft =) (size_t) 0U, - SODIUM_C99(.initialized =) 0 + SODIUM_C99(.initialized =) 0, + SODIUM_C99(.getrandom_available =) 0 }; static uint64_t @@ -86,14 +91,14 @@ sodium_hrtime(void) #ifndef _WIN32 static ssize_t -safe_read(const int fd, void * const buf_, size_t count) +safe_read(const int fd, void * const buf_, size_t size) { unsigned char *buf = (unsigned char *) buf_; ssize_t readnb; - assert(count > (size_t) 0U); + assert(size > (size_t) 0U); do { - while ((readnb = read(fd, buf, count)) < (ssize_t) 0 && + while ((readnb = read(fd, buf, size)) < (ssize_t) 0 && (errno == EINTR || errno == EAGAIN)); /* LCOV_EXCL_LINE */ if (readnb < (ssize_t) 0) { return readnb; /* LCOV_EXCL_LINE */ @@ -101,9 +106,9 @@ safe_read(const int fd, void * const buf_, size_t count) if (readnb == (ssize_t) 0) { break; /* LCOV_EXCL_LINE */ } - count -= (size_t) readnb; + size -= (size_t) readnb; buf += readnb; - } while (count > (ssize_t) 0); + } while (size > (ssize_t) 0); return (ssize_t) (buf - (unsigned char *) buf_); } @@ -145,6 +150,42 @@ randombytes_salsa20_random_random_dev_open(void) /* LCOV_EXCL_STOP */ } +#ifdef SYS_getrandom +static int +_randombytes_linux_getrandom(void * const buf, const size_t size) +{ + int readnb; + + assert(size <= 256U); + do { + readnb = syscall(SYS_getrandom, buf, (int) 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 randombytes_salsa20_random_init(void) { @@ -153,6 +194,19 @@ randombytes_salsa20_random_init(void) stream.nonce = sodium_hrtime(); assert(stream.nonce != (uint64_t) 0U); +# ifdef SYS_getrandom + { + unsigned char fodder[16]; + + if (randombytes_linux_getrandom(fodder, sizeof fodder) == 0) { + stream.getrandom_available = 1; + errno = errno_save; + return; + } + stream.getrandom_available = 0; + } +# endif + if ((stream.random_data_source_fd = randombytes_salsa20_random_random_dev_open()) == -1) { abort(); /* LCOV_EXCL_LINE */ @@ -191,10 +245,23 @@ randombytes_salsa20_random_stir(void) stream.initialized = 1; } #ifndef _WIN32 - if (safe_read(stream.random_data_source_fd, m0, +# ifdef SYS_getrandom + if (stream.getrandom_available != 0) { + if (randombytes_linux_getrandom(m0, sizeof m0) != 0) { + abort(); /* LCOV_EXCL_LINE */ + } + } else if (stream.random_data_source_fd == -1 || + safe_read(stream.random_data_source_fd, m0, + sizeof m0) != (ssize_t) sizeof m0) { + abort(); /* LCOV_EXCL_LINE */ + } +# else + if (stream.random_data_source_fd == -1 || + safe_read(stream.random_data_source_fd, m0, sizeof m0) != (ssize_t) sizeof m0) { abort(); /* LCOV_EXCL_LINE */ } +# endif #else /* _WIN32 */ if (! RtlGenRandom((PVOID) m0, (ULONG) sizeof m0)) { abort(); /* LCOV_EXCL_LINE */ @@ -277,6 +344,11 @@ randombytes_salsa20_random_close(void) stream.initialized = 0; ret = 0; } +# ifdef SYS_getrandom + if (stream.getrandom_available != 0) { + ret = 0; + } +# endif #else /* _WIN32 */ if (stream.initialized != 0) { stream.initialized = 0; diff --git a/src/libsodium/randombytes/sysrandom/randombytes_sysrandom.c b/src/libsodium/randombytes/sysrandom/randombytes_sysrandom.c index de03201e..5d836a12 100644 --- a/src/libsodium/randombytes/sysrandom/randombytes_sysrandom.c +++ b/src/libsodium/randombytes/sysrandom/randombytes_sysrandom.c @@ -4,6 +4,9 @@ # include # include #endif +#ifdef __linux__ +# include +#endif #include #include @@ -60,23 +63,25 @@ randombytes_sysrandom_close(void) typedef struct SysRandom_ { int random_data_source_fd; int initialized; + int getrandom_available; } SysRandom; static SysRandom stream = { SODIUM_C99(.random_data_source_fd =) -1, - SODIUM_C99(.initialized =) 0 + SODIUM_C99(.initialized =) 0, + SODIUM_C99(.getrandom_available =) 0 }; #ifndef _WIN32 static ssize_t -safe_read(const int fd, void * const buf_, size_t count) +safe_read(const int fd, void * const buf_, size_t size) { unsigned char *buf = (unsigned char *) buf_; ssize_t readnb; - assert(count > (size_t) 0U); + assert(size > (size_t) 0U); do { - while ((readnb = read(fd, buf, count)) < (ssize_t) 0 && + while ((readnb = read(fd, buf, size)) < (ssize_t) 0 && (errno == EINTR || errno == EAGAIN)); /* LCOV_EXCL_LINE */ if (readnb < (ssize_t) 0) { return readnb; /* LCOV_EXCL_LINE */ @@ -84,9 +89,9 @@ safe_read(const int fd, void * const buf_, size_t count) if (readnb == (ssize_t) 0) { break; /* LCOV_EXCL_LINE */ } - count -= (size_t) readnb; + size -= (size_t) readnb; buf += readnb; - } while (count > (ssize_t) 0); + } while (size > (ssize_t) 0); return (ssize_t) (buf - (unsigned char *) buf_); } @@ -128,10 +133,59 @@ randombytes_sysrandom_random_dev_open(void) /* LCOV_EXCL_STOP */ } +# ifdef SYS_getrandom +static int +_randombytes_linux_getrandom(void * const buf, const size_t size) +{ + int readnb; + + assert(size <= 256U); + do { + readnb = syscall(SYS_getrandom, buf, (int) 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 randombytes_sysrandom_init(void) { - const int errno_save = errno; + const int errno_save = errno; + +# ifdef SYS_getrandom + { + unsigned char fodder[16]; + + if (randombytes_linux_getrandom(fodder, sizeof fodder) == 0) { + stream.getrandom_available = 1; + errno = errno_save; + return; + } + stream.getrandom_available = 0; + } +# endif if ((stream.random_data_source_fd = randombytes_sysrandom_random_dev_open()) == -1) { @@ -177,6 +231,11 @@ randombytes_sysrandom_close(void) stream.initialized = 0; ret = 0; } +# ifdef SYS_getrandom + if (stream.getrandom_available != 0) { + ret = 0; + } +# endif #else /* _WIN32 */ if (stream.initialized != 0) { stream.initialized = 0; @@ -205,7 +264,16 @@ randombytes_sysrandom_buf(void * const buf, const size_t size) assert(size <= ULONG_LONG_MAX); #endif #ifndef _WIN32 - if (safe_read(stream.random_data_source_fd, buf, size) != (ssize_t) size) { +# ifdef SYS_getrandom + if (stream.getrandom_available != 0) { + if (randombytes_linux_getrandom(buf, size) != 0) { + abort(); + } + return; + } +# endif + if (stream.random_data_source_fd == -1 || + safe_read(stream.random_data_source_fd, buf, size) != (ssize_t) size) { abort(); /* LCOV_EXCL_LINE */ } #else