Understanding FreeBSD's Random Number Subsystem (random(4)) and Entropy Harvesting
How FreeBSD gathers entropy from interrupt timing and hardware sources, feeds it into Fortuna, and guarantees /dev/random never blocks without silently becoming predictable.
A cryptographic random number generator has exactly one job that matters more than any other: never produce output an attacker can predict, even partially. FreeBSD’s random(4) subsystem is built around that constraint specifically, and its design — a Fortuna-based CSPRNG fed by harvested entropy from a deliberately wide set of hardware and timing sources — is worth understanding beyond “it’s the thing behind /dev/random.”
Why FreeBSD doesn’t distinguish /dev/random from /dev/urandom
Historically, some Unix systems drew a hard line between /dev/random (blocks when the system believes it lacks sufficient entropy) and /dev/urandom (never blocks, even if the underlying pool is weak). FreeBSD collapsed this distinction: both device nodes are backed by the same CSPRNG, and neither blocks once the generator has been seeded at boot. The reasoning is that a properly designed CSPRNG, once seeded with even a modest amount of real entropy, is computationally indistinguishable from a true random source for any practical output volume — the “urandom might run out and become weak” fear reflects generator designs simpler than what FreeBSD actually runs. The one place FreeBSD does block is early boot, before the generator has been seeded at all — reads against an unseeded generator block until seeding completes, rather than returning predictable output.
Fortuna: reseeding architecture, not just an algorithm
FreeBSD’s generator implements Fortuna, a CSPRNG design specifically built around a threat model of partial generator compromise. The core idea: entropy harvested from various sources is fed into a set of pools (32 in FreeBSD’s implementation), and instead of using every pool for every reseed, the generator uses pool n only once every 2^n reseed events. Pool 0 feeds every reseed, pool 1 every other one, pool 2 every fourth, and so on.
The reason for this pooling scheme is subtle and specifically defensive: if an attacker somehow learns the internal state of the generator at some point in time, Fortuna’s design guarantees the state will still recover to unpredictability, because slower-cycling, higher-numbered pools keep accumulating entropy the attacker didn’t observe, and eventually one of them gets folded back into the generator’s state during a reseed the attacker can’t predict or fully account for. A generator that just XORed all incoming entropy into one running pool wouldn’t have this self-healing property — full compromise of its state would compromise all future output until enough fresh entropy overwhelmed the known bits, with no structural guarantee of when that happens. Fortuna’s pooling gives that guarantee an actual mathematical bound.
Where the entropy actually comes from
The harvesting side is intentionally broad rather than relying on one privileged source. FreeBSD’s entropy harvesting subsystem pulls timing and value data from interrupt handlers (the precise timing of hardware interrupts firing is inherently somewhat unpredictable relative to any external observer), keyboard and mouse input timing where available, and — where present — dedicated hardware sources: Intel’s RDRAND/RDSEED instructions, VIA’s PadLock RNG, and other hardware TRNGs exposed via the random(4) framework’s pluggable source model.
Critically, hardware RNG output is treated as one input among several, not as a trusted, unconditional replacement for the software-harvested entropy pool. This design choice is deliberate and directly addresses a real, documented category of concern: a compromised or backdoored hardware RNG that always returns attacker-known values would, if trusted exclusively, silently destroy the security of every key ever generated on the system. By mixing hardware RNG output into the same Fortuna pools as interrupt-timing entropy rather than using it as a sole source, FreeBSD ensures that even a fully compromised hardware source can only ever reduce the entropy contributed, not unilaterally control the generator’s output — the other harvested sources still contribute unpredictability the hardware source doesn’t know.
Seeding at boot, and why it used to be a genuine problem
The hardest moment for any entropy subsystem is the first few seconds after boot, before interrupt timing has accumulated meaningfully and before disk I/O patterns exist to harvest from. FreeBSD addresses this with a persistent entropy cache: at shutdown (and periodically during uptime), the kernel writes a snapshot of harvested entropy state to disk, and at the next boot, that cached state is loaded early and fed into the generator before anything security-sensitive runs, rather than starting the generator from nothing.
This matters most acutely for freshly-provisioned virtual machines and appliances — a VM cloned from a template image, booting for the first time, has no meaningfully unique interrupt-timing history yet, and if every clone of that template seeded identically, every clone could end up with correlated or predictable early-boot randomness. FreeBSD’s /etc/rc.d/random boot script and the random(4) framework are specifically designed to detect this class of situation (an entropy cache file that’s missing, empty, or suspiciously identical to a known template state) and treat it as “unseeded” rather than trusting a cache file that might not represent genuine local entropy at all.
Checking the subsystem’s actual state
sysctl kern.random exposes the harvesting subsystem’s live state, including per-source harvest statistics and which hardware sources the framework has detected and is drawing from:
sysctl kern.random.harvest
This is useful less as a day-to-day administrative tool and more as a way to confirm, on unfamiliar or embedded hardware, exactly which entropy sources the running kernel actually believes it has access to — a headless appliance with no keyboard, no mouse, and a single spinning disk has a meaningfully smaller natural entropy-harvesting surface than a general-purpose workstation, and knowing that is the first step in deciding whether additional hardware entropy sources are worth adding to a given deployment.
The overall design — Fortuna’s self-healing pool structure, broad and non-exclusive entropy sourcing, and persistent cross-boot seeding — reflects a subsystem built by people who assumed some part of it would eventually be compromised or under-resourced, and engineered the whole chain to degrade gracefully rather than fail catastrophically and silently.