Skip to content

Use getrandom() in Linux instead of /dev/urandom #13

@oittaa

Description

@oittaa

Using getrandom() instead of opening /dev/urandom is the preferred way to get random bytes in modern Linux systems.

Something like the following could be used in src/random/random.c:

/********************************************************************************************
* Hardware-based random number generation function
*
* It uses /dev/urandom in Linux and CNG's BCryptGenRandom function in Windows
*********************************************************************************************/ 

#include "random.h"
#include <stdlib.h>
#if defined(__WINDOWS__)
    #include <windows.h>
    #include <bcrypt.h>
#elif defined(__LINUX__)
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/random.h>
    #include <errno.h>
    static int lock = -1;
    static int getrandom_works = 1;
#endif

#define passed 0 
#define failed 1


static __inline void delay(unsigned int count)
{
    while (count--) {}
}


int randombytes(unsigned char* random_array, unsigned long long nbytes)
{ // Generation of "nbytes" of random values
    
#if defined(__WINDOWS__)   
    if (!BCRYPT_SUCCESS(BCryptGenRandom(NULL, random_array, (unsigned long)nbytes, BCRYPT_USE_SYSTEM_PREFERRED_RNG))) {
        return failed;
    }

#elif defined(__LINUX__)
    int r, n = (int)nbytes, count = 0;
    
    if (getrandom_works == 1) {
        errno = 0;
        while (n > 0) {
            r = getrandom(random_array+count, n, 0);
            if (r < 0) {
                if (errno == EINTR) {
                    /* retry getrandom() if it was interrupted by a signal */
                    continue;
                }
                getrandom_works = 0;
                break;
            }
            count += r;
            n -= r;
        }
        if (n == 0) {
            return passed;
        }
    }

    if (lock == -1) {
        do {
            lock = open("/dev/urandom", O_RDONLY);
            if (lock == -1) {
                delay(0xFFFFF);
            }
        } while (lock == -1);
    }

    while (n > 0) {
        do {
            r = read(lock, random_array+count, n);
            if (r == -1) {
                delay(0xFFFF);
            }
        } while (r == -1);
        count += r;
        n -= r;
    }
#endif

    return passed;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions