Make sure that the requested number of random bytes is fully read, even if a single read() invocation returned fewer than "count" bytes.

This commit is contained in:
LoRd_MuldeR 2022-02-08 22:46:33 +01:00
parent 956e79ecc6
commit c63c3bffe6
Signed by: mulder
GPG Key ID: 2B5913365F57E03F
3 changed files with 38 additions and 16 deletions

View File

@ -8,7 +8,7 @@
/* Intel(R) oneAPI DPC++/C++ Compiler */ /* Intel(R) oneAPI DPC++/C++ Compiler */
#if defined(__INTEL_LLVM_COMPILER) && (!defined(__GNUC__)) #if defined(__INTEL_LLVM_COMPILER) && (!defined(__GNUC__))
# define __GNUC__ 9 # define __GNUC__ 10
#endif #endif
/* Compiler compatibility */ /* Compiler compatibility */

View File

@ -28,6 +28,7 @@ static INLINE size_t MIN_SIZE(const size_t a, const size_t b) { return (a > b) ?
#ifdef _WIN32 #ifdef _WIN32
# include <Windows.h> # include <Windows.h>
# include <io.h>
#else #else
# include <unistd.h> # include <unistd.h>
# include <pthread.h> # include <pthread.h>
@ -88,12 +89,14 @@ static void win32_call_once(CALL_ONCE_TYPE *const control, void (*init_routine)(
// Random bytes // Random bytes
// ========================================================================== // ==========================================================================
#define MAX_COUNT 1048576U
/* Global state */ /* Global state */
static CALL_ONCE_TYPE s_random_is_initialized = CALL_ONCE_INIT; static CALL_ONCE_TYPE s_random_is_initialized = CALL_ONCE_INIT;
#if defined(_WIN32) #if defined(_WIN32)
typedef BOOLEAN(WINAPI *rtlgenrandom_t)(void *buffer, ULONG length); typedef BOOLEAN(WINAPI *ptr_genrandom_t)(void *buffer, ULONG length);
static HMODULE s_advapi32 = NULL; static HMODULE s_advapi32 = NULL;
static rtlgenrandom_t s_rtlgenrandom = NULL; static ptr_genrandom_t s_genrandom = NULL;
#else #else
static const char *const DEV_RANDOM[] = { "/dev/urandom", "/dev/arandom", "/dev/random", NULL }; static const char *const DEV_RANDOM[] = { "/dev/urandom", "/dev/arandom", "/dev/random", NULL };
static int s_random_fd = -1; static int s_random_fd = -1;
@ -102,8 +105,11 @@ static int s_random_fd = -1;
/* De-initialize CSRNG */ /* De-initialize CSRNG */
static void exit_random_source(void) static void exit_random_source(void)
{ {
#if defined(_WIN32) #ifdef _WIN32
s_rtlgenrandom = NULL; if (s_genrandom)
{
s_genrandom = NULL;
}
if (s_advapi32) if (s_advapi32)
{ {
FreeLibrary(s_advapi32); FreeLibrary(s_advapi32);
@ -121,10 +127,10 @@ static void exit_random_source(void)
/* Initialize CSRNG */ /* Initialize CSRNG */
static void init_random_source(void) static void init_random_source(void)
{ {
#if defined(_WIN32) #ifdef _WIN32
if ((s_advapi32 = LoadLibraryW(L"advapi32.dll"))) if ((s_advapi32 = LoadLibraryW(L"advapi32.dll")))
{ {
s_rtlgenrandom = (rtlgenrandom_t) GetProcAddress(s_advapi32, "SystemFunction036"); s_genrandom = (ptr_genrandom_t) GetProcAddress(s_advapi32, "SystemFunction036");
} }
#else #else
#if defined(GETENTROPY) #if defined(GETENTROPY)
@ -151,27 +157,43 @@ init_completed: ;
/* Generate random bytes */ /* Generate random bytes */
size_t slunkcrypt_random_bytes(uint8_t* const buffer, const size_t length) size_t slunkcrypt_random_bytes(uint8_t* const buffer, const size_t length)
{ {
size_t offset;
CALL_ONCE(&s_random_is_initialized, init_random_source); CALL_ONCE(&s_random_is_initialized, init_random_source);
#if defined(_WIN32) #ifdef _WIN32
if (s_rtlgenrandom) if (s_genrandom)
{ {
const ULONG count = (ULONG) MIN_SIZE(length, ULONG_MAX); ULONG count;
return s_rtlgenrandom(buffer, count) ? count : 0U; for (offset = 0U; offset < length; offset += count)
{
count = (ULONG) MIN_SIZE(length - offset, MAX_COUNT);
if (!s_genrandom(buffer + offset, count))
{
break; /*failed*/
}
}
return offset;
} }
return 0U; return 0U;
#else #else
if (s_random_fd >= 0) if (s_random_fd >= 0)
{ {
const ssize_t result = read(s_random_fd, buffer, length); ssize_t count;
return (result < 0) ? 0U : ((size_t)result); for (offset = 0; offset < length; offset += (size_t)count)
{
if (!((count = read(s_random_fd, buffer + offset, MIN_SIZE(length - offset, MAX_COUNT))) > 0))
{
break; /*failed*/
}
}
return offset;
} }
#if defined(GETENTROPY) #if defined(GETENTROPY)
else else
{ {
size_t offset, count; size_t count;
for (offset = 0U; offset < length; offset += count) for (offset = 0U; offset < length; offset += count)
{ {
count = MIN_SIZE(length - offset, 256U); count = MIN_SIZE(length - offset, 256U); /*the maximum permitted value is 256*/
if (GETENTROPY(buffer + offset, count) < 0) if (GETENTROPY(buffer + offset, count) < 0)
{ {
break; /*failed*/ break; /*failed*/

View File

@ -8,6 +8,6 @@
#define LIB_VERSION_MAJOR 1 #define LIB_VERSION_MAJOR 1
#define LIB_VERSION_MINOR 1 #define LIB_VERSION_MINOR 1
#define LIB_VERSION_PATCH 1 #define LIB_VERSION_PATCH 2
#endif #endif