Random numbers

As mentioned in the PELD spec, it is not so easy to get good pseudo-random numbers in the context of a Live system. This document describes how Tails behaves in this area.

Entropy sources

Tails uses the Linux kernel's entropy gathering facilities.

Entropy pool initialization

The Linux kernel initializes its RNG with various sources, including:

  • Hardware RNGs (if available)
  • CPU instructions like RDSEED, RDRAND, or RDTSC
  • interrupt timings, including input events (keyboard, mouse, etc.)

If the entropy pool is not initialized the first time random numbers are requested, the kernel will block and generate entropy from cycle counter jitter (that's not supported on all architectures, but it is on x86), which takes about a second. There was some scepticism about the quality of this jitter entropy in the past (for example by Theodore Ts'o and Linus Torvalds) but there hasn't been much discussion about it since it was introduced in Linux 5.4 (a publication by the German Federal Office for Information Security validates the jitter entropy as a good source of entropy).

Some sources, like interrupt timings, are continuously mixed into the entropy pool, which is used to periodically reseed the kernel's RNG. This reseeding is done more often during boot, because it's unclear how good the entropy sources are during early boot, and mixing in more entropy is a good way to ensure that the entropy pool is well-seeded.

The userland can also mix in some entropy by writing to /dev/urandom or /dev/random. In Debian, systemd-random-seed.service is used to write a random seed to /var/lib/systemd/random-seed during shutdown and load it into the kernel entropy pool during boot.

That doesn't work in Tails, because of the read-only root filesystem. Instead of systemd-random-seed.service, Tails uses custom scripts executed in the initramfs during boot and before shutdown. The random seed is not stored on the filesystem, but in an otherwise unused sector on the device, at logical block address (LBA) 34 (that's the first sector after the GPT)).

This solves the problem that the root filesystem is read-only in Tails and has multiple advantages:

  • The filesystem is not changed, therefore easier to verify.
  • It doesn't require persistence to be set up.
  • The entropy pool is seeded earlier during the boot process (in the initramfs init-top stage).

The scripts do basically the same systemd-random-seed.service does (see the source code).

During boot:

  1. Read the seed from the location it was stored at.
  2. Write the seed to /dev/urandom, which causes it to be mixed in with the existing bytes in the entropy pool.
  3. Update the seed with random bytes from /dev/urandom to ensure that some entropy is saved for the next boot, even if the system is not shutting down properly.

During shutdown:

  • Update the seed with random bytes from /dev/urandom to save the entropy gathered during the session.

Sources to learn more about the Linux kernel's RNG and its recent changes:

Initialization during installation

When creating a new Tails device, Tails Cloner writes a random seed to LBA 34 to initialize the seed for the first boot.

However, this is not the case for Tails installed from a USB image, which is the most common use case.

Possible disadvantages

On #11897, the concern was raised that writing to the Tails device on each boot might allow a sophisticated attacker with physical access to the device to determine how many times it has been booted due to the wear leveling of the flash memory.

We try to mitigate this by writing the random seed a random number of times (1 to 500) during first boot. This should make it harder to determine the number of boots by looking at the wear leveling of the flash memory. Concerns that this might not be enough if the device uses static wear leveling have been raised on #11897.