diff --git a/src/random/random.c b/src/random/random.c index cf0a0db..686ec7d 100644 --- a/src/random/random.c +++ b/src/random/random.c @@ -2,7 +2,7 @@ * Hardware-based random number generation function * * It uses /dev/urandom in Linux and CNG's BCryptGenRandom function in Windows -*********************************************************************************************/ +*********************************************************************************************/ #include "random.h" #include @@ -10,12 +10,21 @@ #include #include #elif defined(__LINUX__) - #include - #include - static int lock = -1; + #if defined(__has_include) + #if __has_include() + #define HAVE_GETRANDOM 1 + #include + #include + #endif + #endif + #ifndef HAVE_GETRANDOM + #include + #include + static int lock = -1; + #endif #endif -#define passed 0 +#define passed 0 #define failed 1 @@ -28,7 +37,7 @@ static __inline void delay(unsigned int count) int randombytes(unsigned char* random_array, unsigned long long nbytes) { // Generation of "nbytes" of random values -#if defined(__WINDOWS__) +#if defined(__WINDOWS__) if (!BCRYPT_SUCCESS(BCryptGenRandom(NULL, random_array, (unsigned long)nbytes, BCRYPT_USE_SYSTEM_PREFERRED_RNG))) { return failed; } @@ -36,6 +45,21 @@ int randombytes(unsigned char* random_array, unsigned long long nbytes) #elif defined(__LINUX__) int r, n = (int)nbytes, count = 0; + #if defined(HAVE_GETRANDOM) + while (n > 0) { + errno = 0; + r = getrandom(random_array+count, n, 0); + if (r < 0) { + if (errno == EINTR) { + /* retry getrandom() if it was interrupted by a signal */ + continue; + } + return failed; + } + count += r; + n -= r; + } + #else /* Not HAVE_GETRANDOM */ if (lock == -1) { do { lock = open("/dev/urandom", O_RDONLY); @@ -55,7 +79,8 @@ int randombytes(unsigned char* random_array, unsigned long long nbytes) count += r; n -= r; } + #endif /* Not HAVE_GETRANDOM */ #endif return passed; -} \ No newline at end of file +}