Why Random Numbers Matter
Every cryptographic guarantee — confidentiality, integrity, authenticity — sits on top of one assumption: an attacker cannot predict the secret values a system uses. Keys, initialization vectors, nonces, and salts are only as strong as the process that generated them. A cipher can be mathematically perfect and still fail completely if its inputs are guessable.
Two sources of "random"
Pseudo-random (PRNG): deterministic algorithm, same seed → same output forever.
Fast, but predictable if the seed is known or guessable (e.g. Date.now(), a counter, a weak
library default).
Cryptographically secure (CSPRNG): designed so that even seeing prior outputs gives no
advantage in predicting future ones (e.g. crypto.getRandomValues(), /dev/urandom).
This is the only category that belongs in key/nonce generation.
What goes wrong
Historic real-world failures nearly all trace back to this: Debian's 2008 OpenSSL bug (predictable
keys from a crippled entropy pool), WEP's small/reused IVs, mobile apps seeding keys from timestamps,
and "random" lottery/CTF tokens generated from rand() seeded by the process start time.
The lesson is the same every time: attackers don't break the math — they find the shortcut around it.
Live demo — timestamp-seeded key vs. CSPRNG key
Both "keys" below are 128 bits (32 hex characters). One is generated from a predictable seed (current time in milliseconds, the kind of shortcut real bugs have used); the other from a real CSPRNG. They look equally random at a glance — the difference is in how hard each is to reproduce.
If an attacker knows roughly when a weak key was generated (say, within a 10-second login window), they only need to try ≈ 10,000 millisecond values — not 2128. Knowing the algorithm collapses the search space from astronomical to trivial. This is why key generation must use a CSPRNG, never a value derived from time, a counter, or user input alone.
The Nonce — "Number Used Once"
A nonce is a value that must never be reused with the same key. In stream ciphers and counter-mode block ciphers (CTR, GCM), the nonce combines with the key to produce a unique keystream for every message. Reuse the same (key, nonce) pair twice, and you reuse the exact same keystream — which breaks the encryption even without ever recovering the key.
The math in one line
Encryption: C = P ⊕ keystream(key, nonce). If two messages P1 and P2 are
encrypted under the same keystream:
C1 ⊕ C2 = (P1 ⊕ K) ⊕ (P2 ⊕ K) = P1 ⊕ P2
The keystream K cancels out entirely. The attacker never touches the key, yet
recovers the XOR of the two plaintexts — and with known-plaintext tricks or letter-frequency
analysis, often both plaintexts outright. This exact flaw broke WEP and has recurred in countless
"roll your own crypto" implementations.
Live demo — nonce reuse vs. nonce discipline
This uses a simplified deterministic keystream generator for teaching purposes only (not a real cipher) — the vulnerability it demonstrates is identical to real stream ciphers.
N-002) and re-run.Key Space Calculator
Key space (the total number of possible keys/passwords) is charset_size ^ length.
Every character added to the alphabet, or to the length, multiplies the attacker's work — but not
equally. Length grows the exponent; alphabet size grows the base. Both matter, but they don't matter
the same amount per character added.
Fixed comparison — same lengths, three alphabets
a–z (26 chars) | a–z + 0–9 (36 chars) | a–z + A–Z + 0–9 + specials (94 chars)