Presentation of Random Number Generator

The Random Number Generator or RNG is a mechanism in charge of producing pseudo random numbers. These numbers are then used for generating SSH keys, random PIDs for processes, TCP sequence numbers, and UUIDs for example. Using encryption (file systems, mails, etc) consumes a lot of pseudo random numbers.

To get good pseudo random numbers, you need some entropy. Entropy is defined as randomness collected by an operating system (see Wikipedia definition about Entropy).

This entropy may be provided by:

some internal sources like keyboard timings, network traffic, mouse movements, interrupt, and IDE timings,

a specific processor instruction like RDRAND available in some Intel IvyBridge and Haswell processors,

available in some and processors, the physical host in the case of virtual machines through the virtio-rng paravirtualized device (see this Red Hat article about Access to Random Numbers Made Easy in RHEL 7),

paravirtualized device (see this article about Access to Random Numbers Made Easy in RHEL 7), a dedicated, external, physical device (this solution, called TPM for Trusted Platform Module, is useful for large consumers of pseudo random numbers).

It is interesting to note that entropy doesn’t come from a single source in the Linux kernel but from several ones.

To allow applications to get pseudo random numbers, at least two kernel devices exist:

/dev/urandom gives standard quality numbers but doesn’t stop whatever the entropy available: when asking for a lot of pseudo random numbers, their quality decreases,

gives standard quality numbers but doesn’t stop whatever the entropy available: when asking for a lot of pseudo random numbers, their quality decreases, /dev/random provides high quality numbers but stops when entropy is poor: the Linux kernel keeps a entropy pool of 4 KB (see /proc/sys/kernel/random/poolsize); when the pool is empty, the kernel blocks causing a delay until it can provide the requested random numbers.

Because of the blocking behaviour, lack of entropy may cause performance problems.

Prerequisites

Before going further, you need to install the rng-tools package if not already there:

# yum install -y rng-tools

Configuration Check

To know which sources of entropy are available in a given system (outside basic sources like keyboard timings, mouse movements, etc), type:

# rngd -v Unable to open file: /dev/tpm0 Available entropy sources: DRNG

Note1: On this system, there isn’t any external, physical device (TPM) because /dev/tpm0 is missing.

Note2: But there is a DRNG entropy source: DRNG stands for Digital Random Number Generator; it is an Intel ‘hardware approach to high-quality, high-performance entropy and random number generation’ using the RDRAND processor instruction (see this document about DRNG for more details).

Note3: You can check if your processor has got the RDRAND instruction by typing:

# cat /proc/cpuinfo | grep rdrand

If you run the rngd -v command in a virtual machine or a physical machine without DRNG/TPM, you should get the following result:

# rngd -v Unable to open file: /dev/tpm0 can't open any entropy source Maybe RNG device modules are not loaded

Note: The last message means: if you’ve got an external, physical device, you forgot to load the associated module. As most of the servers don’t have this kind of module, you can safely ignore this message.

The rngd Service

If you are lucky enough to have a hardware source of entropy (DRNG or TPM), it’s a good idea to start the rngd service at the host level. Its purpose is to permanently collect entropy coming from the different hardware sources and mix them with the software sources of entropy.

Start the rngd service:

# systemctl start rngd

To check the status of the rngd service, type:

# systemctl status rngd rngd.service - Hardware RNG Entropy Gatherer Daemon Loaded: loaded (/usr/lib/systemd/system/rngd.service; enabled) Active: active (running) since Wed 2015-09-30 19:19:22 CEST; 8min ago Main PID: 7401 (rngd) CGroup: /system.slice/rngd.service └─7401 /sbin/rngd -f Sep 30 19:19:22 host.example.com systemd[1]: Started Hardware RNG Entropy .... Sep 30 19:19:22 host.example.com rngd[7401]: Unable to open file: /dev/tpm0 Hint: Some lines were ellipsized, use -l to show in full.

If you run the same command in a virtual machine or a server without DNRG/TPM, you get the following result (the -l option has been added for clarity):

# systemctl status rngd -l rngd.service - Hardware RNG Entropy Gatherer Daemon Loaded: loaded (/usr/lib/systemd/system/rngd.service; enabled) Active: failed (Result: exit-code) since Wed 2015-09-30 19:51:35 CEST; 12min ago Process: 588 ExecStart=/sbin/rngd -f (code=exited, status=1/FAILURE) Main PID: 588 (code=exited, status=1/FAILURE) CGroup: /system.slice/rngd.service Sep 30 19:51:35 vm.example.com systemd[1]: Started Hardware RNG Entropy Gatherer Daemon. Sep 30 19:51:35 vm.example.com rngd[588]: Unable to open file: /dev/tpm0 Sep 30 19:51:35 vm.example.com rngd[588]: can't open any entropy source Sep 30 19:51:35 vm.example.com rngd[588]: Maybe RNG device modules are not loaded Sep 30 19:51:35 vm.example.com systemd[1]: rngd.service: main process exited, code=exited, status=1/FAILURE Sep 30 19:51:35 vm.example.com systemd[1]: Unit rngd.service entered failed state.

This is not a bug as I first thought. The rngd service doesn’t start when no hardware entropy source is available. There is simply nothing to mix!

If you really need to run the rngd service or if your application is blocked when asking for pseudo random numbers through the /dev/random device, there is a pseudo solution: you can configure the rngd service to get its entropy from the /dev/urandom device and feeds the /dev/random device.

Caution: This is a pseudo solution because you fill in the /dev/random device with data from the /dev/urandom device: the quality of the pseudo random numbers delivered by the /dev/random device is simply lower. This can be a real problem if these numbers produce SSH keys for example.

To be able to run the rngd service without hardware entropy source, create a copy of the rngd.service unit file:

# cp /usr/lib/systemd/system/rngd.service /etc/systemd/system

Edit the /etc/systemd/system/rngd.service file and replace the line starting with ExecStart with:

ExecStart=/sbin/rngd -f -r /dev/urandom

Reload the Systemd configuration:

# systemctl daemon-reload

Restart the rngd service:

# systemctl restart rngd

Check the new service status:

# systemctl status rngd rngd.service - Hardware RNG Entropy Gatherer Daemon Loaded: loaded (/etc/systemd/system/rngd.service; enabled) Active: active (running) since Wed 2015-09-30 19:56:57 CEST; 6s ago Main PID: 24972 (rngd) CGroup: /system.slice/rngd.service └─24972 /sbin/rngd -f -r /dev/urandom Sep 30 19:56:57 vm.example.com systemd[1]: Starting Hardware RNG Entrop.... Sep 30 19:56:57 vm.example.com systemd[1]: Started Hardware RNG Entropy.... Hint: Some lines were ellipsized, use -l to show in full.

The virtio-rng Device

In a virtual machine, you don’t normally get access to a hardware entropy source for at least two reasons:

by definition, as a virtual machine, you use abstraction layers and no hardware devices,

using hardware devices would create fatal dependencies forbidding any host migration.

To solve this problem, QEMU/KVM developers created the virtio-rng device. Entropy available at the host level can now be sent at the guest level through this device.

To make host entropy available to a guest (here vm.example.com), type:

# virsh shutdown vm.example.com # virsh edit vm.example.com

Paste the following lines below the <devices> stanza:

<rng model='virtio'> <backend model='random'>/dev/random</backend> </rng>

Note: Just after <rng model=’virtio’>, you can add a line like <rate bytes=’1024′ period=’1000’/> to prevent a guest from consuming more than 1 KB per second of pseudo random numbers. Otherwise, one single guest could consume all the available pseudo random numbers at the expense of all the others.

Restart the guest:

# virsh start vm.example.com

If you connect to the guest, you will see a new device called /dev/hwrng. This device now transparently feeds the /dev/random device with high-quality pseudo random numbers.

To check the configuration, type:

# systemctl stop rngd # rngd -v Available entropy sources: Intel/AMD hardware rng

Note: For a unknown reason, you need to stop the rngd daemon before running the rngd -v command.

On a KVM host, to get the name of all the virtual machines using the virtio-rng device, type:

# lsof /dev/random | grep qemu-kvm | awk '{print $2;}' | xargs ps -c | awk '{print $9;}' vm.example.com

The haveged Service

If the previous options aren’t good enough for your needs, there is still a solution.

HAVEGE is a random number generator that exploits the modifications of the internal CPU hardware states (caches, branch predictors, TLBs) as a source of uncertainty.

The HAVEGE algorithm has given birth to the haveged service available in the EPEL repository.

To get the benefit of this algorithm, install the EPEL repository:

# yum install epel-release

Then, install the haveged service:

# yum install haveged

Testing Time

To get an idea of how fast the entropy pool is being replenished, type:

# watch -n 1 cat /proc/sys/kernel/random/entropy_avail

Note: Because of the 4 KB entropy pool, you can’t get any value bigger than 4095.

To test the quality of the current sources of entropy, type:

# cat /dev/random | rngtest -c 1000 rngtest 5 Copyright (c) 2004 by Henrique de Moraes Holschuh This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. rngtest: starting FIPS tests... rngtest: bits received from input: 20000032 rngtest: FIPS 140-2 successes: 1000 rngtest: FIPS 140-2 failures: 0 rngtest: FIPS 140-2(2001-10-10) Monobit: 0 rngtest: FIPS 140-2(2001-10-10) Poker: 0 rngtest: FIPS 140-2(2001-10-10) Runs: 0 rngtest: FIPS 140-2(2001-10-10) Long run: 0 rngtest: FIPS 140-2(2001-10-10) Continuous run: 0 rngtest: input channel speed: (min=3.295; avg=6.691; max=54.340)Mibits/s rngtest: FIPS tests speed: (min=117.738; avg=154.840; max=174.986)Mibits/s rngtest: Program run time: 2974188 microseconds

Additional Resources

You can also read:

Finally, you can watch Andrew Mallett‘s video about the rngd service problem (it was this video that sparked the writing of this article).