How to use /dev/random or urandom in C?

CLinuxRandom

C Problem Overview


I want to use /dev/random or /dev/urandom in C. How can I do it? I don't know how can I handle them in C, if someone knows please tell me how. Thank you.

C Solutions


Solution 1 - C

In general, it's a better idea to avoid opening files to get random data, because of how many points of failure there are in the procedure.

On recent Linux distributions, the getrandom system call can be used to get crypto-secure random numbers, and it cannot fail if GRND_RANDOM is not specified as a flag and the read amount is at most 256 bytes.

As of October 2017, OpenBSD, Darwin and Linux (with -lbsd) now all have an implementation of arc4random that is crypto-secure and that cannot fail. That makes it a very attractive option:

char myRandomData[50];
arc4random_buf(myRandomData, sizeof myRandomData); // done!

Otherwise, you can use the random devices as if they were files. You read from them and you get random data. I'm using open/read here, but fopen/fread would work just as well.

int randomData = open("/dev/urandom", O_RDONLY);
if (randomData < 0)
{
	// something went wrong
}
else
{
	char myRandomData[50];
	ssize_t result = read(randomData, myRandomData, sizeof myRandomData);
	if (result < 0)
	{
		// something went wrong
	}
}

You may read many more random bytes before closing the file descriptor. /dev/urandom never blocks and always fills in as many bytes as you've requested, unless the system call is interrupted by a signal. It is considered cryptographically secure and should be your go-to random device.

/dev/random is more finicky. On most platforms, it can return fewer bytes than you've asked for and it can block if not enough bytes are available. This makes the error handling story more complex:

int randomData = open("/dev/random", O_RDONLY);
if (randomData < 0)
{
	// something went wrong
}
else
{
	char myRandomData[50];
	size_t randomDataLen = 0;
	while (randomDataLen < sizeof myRandomData)
	{
		ssize_t result = read(randomData, myRandomData + randomDataLen, (sizeof myRandomData) - randomDataLen);
		if (result < 0)
		{
			// something went wrong
		}
		randomDataLen += result;
	}
	close(randomData);
}

Solution 2 - C

There are other accurate answers above. I needed to use a FILE* stream, though. Here's what I did...

int byte_count = 64;
char data[64];
FILE *fp;
fp = fopen("/dev/urandom", "r");
fread(&data, 1, byte_count, fp);
fclose(fp);

Solution 3 - C

Just open the file for reading and then read data. In C++11 you may wish to use std::random_device which provides cross-platform access to such devices.

Solution 4 - C

Zneak is 100% correct. Its also very common to read a buffer of random numbers that is slightly larger than what you'll need on startup. You can then populate an array in memory, or write them to your own file for later re-use.

A typical implementation of the above:

typedef struct prandom {
     struct prandom *prev;
     int64_t number;
     struct prandom *next;
} prandom_t;

This becomes more or less like a tape that just advances which can be magically replenished by another thread as needed. There are a lot of services that provide large file dumps of nothing but random numbers that are generated with much stronger generators such as:

  • Radioactive decay
  • Optical behavior (photons hitting a semi transparent mirror)
  • Atmospheric noise (not as strong as the above)
  • Farms of intoxicated monkeys typing on keyboards and moving mice (kidding)

Don't use 'pre-packaged' entropy for cryptographic seeds, in case that doesn't go without saying. Those sets are fine for simulations, not fine at all for generating keys and such.

Not being concerned with quality, if you need a lot of numbers for something like a monte carlo simulation, it's much better to have them available in a way that will not cause read() to block.

However, remember, the randomness of a number is as deterministic as the complexity involved in generating it. /dev/random and /dev/urandom are convenient, but not as strong as using a HRNG (or downloading a large dump from a HRNG). Also worth noting that /dev/random refills via entropy, so it can block for quite a while depending on circumstances.

Solution 5 - C

zneak's answer covers it simply, however the reality is more complicated than that. For example, you need to consider whether /dev/{u}random really is the random number device in the first place. Such a scenario may occur if your machine has been compromised and the devices replaced with symlinks to /dev/zero or a sparse file. If this happens, the random stream is now completely predictable.

The simplest way (at least on Linux and FreeBSD) is to perform an ioctl call on the device that will only succeed if the device is a random generator:

int data;
int result = ioctl(fd, RNDGETENTCNT, &data); 
// Upon success data now contains amount of entropy available in bits

If this is performed before the first read of the random device, then there's a fair bet that you've got the random device. So @zneak's answer can better be extended to be:

int randomData = open("/dev/random", O_RDONLY);
int entropy;
int result = ioctl(randomData, RNDGETENTCNT, &entropy);

if (!result) {
   // Error - /dev/random isn't actually a random device
   return;
}

if (entropy < sizeof(int) * 8) {
    // Error - there's not enough bits of entropy in the random device to fill the buffer
    return;
}

int myRandomInteger;
size_t randomDataLen = 0;
while (randomDataLen < sizeof myRandomInteger)
{
    ssize_t result = read(randomData, ((char*)&myRandomInteger) + randomDataLen, (sizeof myRandomInteger) - randomDataLen);
    if (result < 0)
    {
        // error, unable to read /dev/random 
    }
    randomDataLen += result;
}
close(randomData);

The Insane Coding blog covered this, and other pitfalls not so long ago; I strongly recommend reading the entire article. I have to give credit to their where this solution was pulled from.

Edited to add (2014-07-25)...
Co-incidentally, I read last night that as part of the LibReSSL effort, Linux appears to be getting a GetRandom() syscall. As at time of writing, there's no word of when it will be available in a kernel general release. However this would be the preferred interface to get cryptographically secure random data as it removes all pitfalls that access via files provides. See also the LibReSSL possible implementation.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionstojanceView Question on Stackoverflow
Solution 1 - CzneakView Answer on Stackoverflow
Solution 2 - CDustin KirklandView Answer on Stackoverflow
Solution 3 - CTronicView Answer on Stackoverflow
Solution 4 - CTim PostView Answer on Stackoverflow
Solution 5 - CChris JView Answer on Stackoverflow