Random numbers from the Linux kernel

0

I recently shared a Guess the number game to demonstrate a few “first concepts” in C programming. Whenever I learn a new programming language, I like to start with this simple number-guessing game because it exercises the basics of programming, including how to store values in variables and how to compare values.

That program used the rand function to generate pseudo-random values between zero and some large maximum value. Pseudo-random numbers are okay if you aren’t working on anything very sensitive—and writing a number-guessing game is pretty straightforward. But if you need to have more randomness to the random numbers you generate, you should instead use the getrandom system call in the Linux kernel.

Random bits

A system call acts like a function when you use it in a program, but behind the scenes it interacts directly with the Linux kernel. The getrandom system call prompts the kernel to generate a series of random bits (ones and zeroes) to “fill” a variable.

Use the getrandom system call like this:

ssize_t getrandom(void buf, size_t buflen, unsigned int flags);

The buf buffer should be the address to a variable, so the system call can fill this variable directly. The buflen value tells getrandom how many bytes to fill.

Note that the flags value indicates whether the random number should be blocking (GRND_RANDOM) or nonblocking (GRND_NONBLOCK). This is important because if the random number source on the system hasn’t been initialized yet, or if the source doesn’t contain enough entropy, then using GRND_RANDOM with the getrandom call will wait for the source to fill up with enough random data before the system call will return its own random bits.

On a desktop system where the user frequently uses the mouse, clicks buttons in apps, and types on the keyboard, the system entropy should be high enough to instantly generate a few bytes of random data. But if you’re not sure, you can use GRND_NONBLOCK to prevent blocking, and the system will generate other random bits on its own.

You can see this in action by writing a very short sample program:

#include <stdio.h>
#include <sys/random.h>

int main()
{
  unsigned int num;

  getrandom(&num, sizeof(unsigned int), GRND_NONBLOCK);
  printf("%u\n", num);

  return 0;
}

Every time you run the program, the program will use the getrandom system call to generate random bits in the num variable, which it then prints. Note that getrandom creates random bits; if you store the result in a signed variable such as a regular int, the result could be positive or negative. In this sample, I’ve stored the result in an unsigned variable, so the result can only be zero or some other positive number.

Updating the number-guessing program

With the getrandom system call, we can update the Guess the number program to generate a truly random secret number. If you recall the previous number-guessing program, it used srand to seed the pseudo-random number generator, and rand to generate new pseudo-random numbers. We can replace this by using randval to generate random data in a variable, then using the modulo (%) operator to “fold” the random number into the range 0 to 99, then add 1 to make the secret value between 1 and 100:

    unsigned int randval, secret;

    getrandom(&randval, sizeof(unsigned int), GRND_NONBLOCK);
    secret = (randval % 100) + 1;

Every time you run the program, the Linux kernel will generate random data in the randval variable, so the value in secret will always be a truly random value between 1 and 100.

The rest of the program is the same. Here’s the completed program:

#include <stdio.h>
#include <sys/random.h>

int main()
{
    unsigned int randval, secret, guess;

    getrandom(&randval, sizeof(unsigned int), GRND_NONBLOCK);
    secret = (randval % 100) + 1;

    puts("Guess a random number from 1 to 100");

    do {
        puts("Your guess:");
        scanf("%d", &guess);

        if (guess < secret) {
            puts("Too low");
        }
        else if (guess > secret) {
            puts("Too high");
        }
    } while (guess != secret);

    puts("That's right!");
    return 0;
}

Guess the number

If we save this updated “Guess the number” program as guess2.c we can compile it like this:

$ gcc -o guess2 guess2.c

And now we can play the number-guessing game as before. The program will use if and else if to indicate if the guess is too low or too high, and exit the program with a “That’s right” message when the guess equals the secret number:

$ ./guess2
Guess a random number from 1 to 100
Your guess:
50
Too high
Your guess:
25
Too low
Your guess:
35
Too high
Your guess:
30
Too high
Your guess:
28
Too low
Your guess:
29
That's right!

Using srand and rand is okay if you don’t mind pseudo-random numbers. But if you need to use random values that are actually random, you should use the getrandom system call instead. Read the manual page (in section 2) to learn more about the getrandom system call:

$ man 2 getrandom

Leave a Reply