skip to content

A cryptographically secure generator is still deterministic once it is seeded. Explain where the initial entropy comes from, what "weak entropy" concretely means, and how two machines running correct code with a correct generator can end up emitting identical keys.

level: seniorimportance: should knowfreq 35%

answer

  1. CSPRNG stretches entropy, never creates it
  2. first boot: pool not initialised
  3. fork / snapshot / golden image = duplicate state
  4. clock+pid seed is enumerable
  5. depletion after seeding is a myth

basics

~20 s

A secure generator expands a seed; it does not create unpredictability. If the seed is guessable or duplicated, so is every output. Duplication happens at first boot before the entropy pool fills, on process fork, on VM snapshot restore, and in cloned machine images.

solid answer

~60 s

A CSPRNG is a deterministic expansion function. All of its unpredictability lives in the seed, drawn from the operating system's entropy pool, which collects timing jitter from interrupts, device events and hardware sources and mixes them into a pool that seeds a stream cipher. Three ways the seed goes wrong: 1. **Not yet seeded.** Early in boot the pool has little entropy. A blocking interface (Linux `getrandom` without the non-blocking flag) waits for initialisation; a legacy device-file read historically did not. Devices generating host keys on first boot are the classic case. 2. **Duplicated state.** A userspace generator's state is copied by `fork()`, by a VM snapshot restore, and by baking a seeded image and cloning it. Every copy then emits the identical stream. The fix is to draw from the OS interface, which detects these transitions, or to reseed on process-identity/boot-identity change. 3. **Seeded from something enumerable** — a clock, a pid, a hostname — which reduces the search space to something brute-forcible offline. After proper initialisation, "running out of entropy" is not a real concern.

go deeper

for a junior

Know that the generator only expands a seed, and that the seed must come from the operating system rather than from the clock. Recognise that the same seed means the same output everywhere.

for a middle

Give the three failure classes and one example each, and be able to explain why hashing more clock values does not add entropy. Know that entropy depletion after initialisation is a myth.

for a senior

Reason about fork, snapshot restore and image cloning explicitly, and about first-boot key generation on appliances and containers; name the fixes (OS interface, reseed on identity change, generate long-lived secrets when warm) and the operational costs.

for a principal

Treat it as a fleet property: where in the build/provision/boot pipeline does each long-lived secret come into existence, is the machine unique at that moment, and what evidence would show a duplicated seed across the fleet before an outsider notices.

## The seed is the whole game A cryptographically secure generator is a deterministic function. Give it the same seed and it emits the same bytes forever. It does not manufacture unpredictability; it *stretches* the unpredictability of its seed over an arbitrarily long output. So the security of every key, token and nonce the process ever emits reduces to one question: how many bits of genuine unpredictability went into the seed, and could anybody else have the same ones? ## Where entropy actually comes from Operating systems collect *physical* unpredictability — quantities that are not a function of anything an attacker can compute: - interrupt and device-event timing at fine granularity (disk, network, keyboard, sensors), - scheduling and cycle-counter jitter, - dedicated hardware sources (on-CPU noise-based instructions, TPMs, hardware RNG devices), - for virtual machines, entropy passed in from the hypervisor. These are mixed into a pool, and the pool seeds a cryptographic generator (modern systems use a stream cipher for output expansion). Applications should read from the OS interface rather than build their own pool, for a reason that is structural rather than stylistic: the kernel is the only component that sees the boot transition, the fork, and the hardware sources. The interfaces diverge in ways worth knowing by name because the divergence is exactly where the bugs are: a modern Linux system exposes a call that blocks until the pool is initialised and then never blocks again, alongside a legacy device file that historically returned output before initialisation; BSD-derived systems expose an always-safe call that is documented never to fail or block; Windows exposes a dedicated cryptographic API. The important property is not which one you name but that all of them are *the OS*, and that the differences are all about the first seconds of boot. ## Failure one: not seeded yet At early boot there has been little I/O, so little entropy has been collected. Any secret generated in that window may come from a nearly-empty pool. The canonical scenario is an appliance, container image or embedded device that generates its long-lived host key on first boot, in a uniform environment, with no disk activity and no user input. Independent devices then produce keys drawn from a tiny effective seed space — and studies of internet-wide key collections have repeatedly found large clusters of devices sharing keys or key factors for exactly this reason. The defence is to use the interface that blocks until initialisation (accepting the boot delay), to supply entropy from the hypervisor or a hardware source, and to generate long-lived secrets *after* the system is warm rather than during first boot. ## Failure two: duplicated state This one is subtle because nothing is weak — the seed was excellent, it is just no longer unique. - **`fork()`**: a userspace generator's state lives in the process's memory, so the child inherits an exact copy. Parent and child now produce identical streams. A pre-forking server that seeds before forking hands every worker the same token sequence. - **VM snapshot / restore**: restoring the same snapshot twice replays the same in-memory generator state in two live machines, which then hand out the same session identifiers. - **Golden images and container layers**: baking a seeded state file (or any "random" value) into an image and cloning it thousands of times distributes one seed to the whole fleet. Defences, in order of strength: draw directly from the OS interface for security-relevant values, so the process holds no long-lived state to duplicate; where a userspace generator is unavoidable, reseed when the process identity or the system's boot identity changes and mark the state pages so they are wiped on fork; never persist generator state into an image. ## Failure three: an enumerable seed Seeding from the clock, the process id, the hostname, the MAC address, or a combination of them feels like mixing but is not. Each contributes only as many bits as the attacker's uncertainty about it, which for a clock at second or even millisecond resolution and a known deployment window is a handful. The attacker regenerates your entire output stream offline. Note that this failure is *invisible* to a code reviewer who only sees "we use the secure generator class" — the defect is in the seeding line. ## The entropy-depletion myth A persistent misconception holds that reading random data "uses up" entropy and that a system can therefore run dry and start producing weak output. Once a cryptographic generator is properly seeded with enough bits (256 is the usual figure), its output is computationally indistinguishable from random no matter how much you read; a stream cipher does not get weaker as it runs. The genuine concern is the *initialisation* boundary and state duplication, not throughput. Adding entropy-gathering daemons or blocking reads at steady state solves a problem that does not exist while the real ones — first boot, forks, clones — remain. ## How to answer State the reduction: a CSPRNG is deterministic, so security equals seed quality times seed uniqueness. Then give the three failure classes with a concrete instance each — pre-initialisation boot, fork/snapshot/image duplication, enumerable seed — and name the structural fix: get seeds from the operating system, and generate long-lived secrets when the system is warm and singular rather than when it is fresh and cloned.

  • Your pre-forking server seeds a userspace generator at startup and then forks sixteen workers. What goes wrong and how do you fix it?
    Each worker inherits an identical copy of the generator state, so all sixteen emit the same sequence of tokens and nonces — collisions that look like impossible coincidences. The fix is to not hold long-lived generator state for security values at all and read from the OS interface per use, or, if a userspace generator is required, to reseed in each child after the fork and mark the state so it is discarded across forks.
  • An embedded appliance must generate its host key during first boot and the blocking entropy call adds ten seconds. What are your options?
    Options in rough order of preference: seed from a hardware entropy source or TPM present on the board; have the hypervisor or provisioning system inject a unique seed per device; defer key generation until after the device is warm and has done real I/O; or accept the blocking delay. What you must not do is switch to a non-blocking legacy interface to make the boot fast — that trades a visible delay for an invisible, permanent weakness in a long-lived key.

The generator is a photocopier, not an author. Feed it a unique original and you get unlimited unique-looking pages; feed a thousand machines the same original and every page in the fleet matches.

saying these in an interview costs you the question

  • "The system ran out of entropy so our random values got weaker" — after proper seeding, output strength does not decay with volume.
  • Seeding from time, pid or hostname and calling it mixed entropy.
  • Baking a seeded generator state or a generated secret into a machine or container image.
  • Assuming a correct generator class makes the code correct without looking at how it was seeded.
  • Switching a blocking entropy read to a non-blocking legacy path to fix a slow boot.

context