The Science of Randomness: How Password Generators Really Work

Every time you click "Generate Password" on a website, something mathematically interesting happens — something that most people never think about and most developers only half-understand. The password that appears in that text field didn't come from thin air. It came from a carefully engineered pipeline of entropy collection, cryptographic transformation, and probabilistic selection. Understanding that pipeline is the difference between trusting your security to a coin flip and trusting it to something actually robust.

Let's pull the curtain back.

What Randomness Actually Means (and Why It's Hard)

Computers are deterministic machines. Given the same inputs, they produce the same outputs — every time, forever. This creates a fundamental problem: how do you produce something genuinely unpredictable from a machine whose entire job is to be predictable?

The answer is that you don't generate randomness. You harvest it from the physical world and then amplify it.

True randomness comes from physical phenomena: the exact timing of keystrokes, the oscillation of hardware clocks, thermal noise in electrical components, network packet arrival jitter, mouse movement paths. None of these are predictable in advance, even in principle. Operating systems collect this entropy continuously, feeding it into a pool — on Linux, that's /dev/random and its non-blocking cousin /dev/urandom; on Windows, it's CryptGenRandom; on macOS, it's /dev/random backed by the Secure Key Store.

But here's the thing: raw entropy is slow to accumulate and inefficient to use directly. You might collect 256 bits of genuine randomness from hardware events, but need thousands of bits to generate a session key, an initialization vector, and a password — all at once. That's where CSPRNGs come in.

CSPRNGs: The Engine Under the Hood

A Cryptographically Secure Pseudorandom Number Generator (CSPRNG) takes a small seed of true entropy and stretches it into an arbitrarily long stream of numbers that are computationally indistinguishable from truly random output. The word "pseudorandom" might sound like a weakness, but it isn't — not when the cryptography is done right.

The two properties that make a PRNG "cryptographically secure" are:

  1. The next-bit test: Given any sequence of bits from the output, an attacker with unlimited computing power cannot predict the next bit with probability greater than 50% in polynomial time.
  2. State compromise extension resistance: If an attacker learns the internal state of the generator at some point in time, they cannot reconstruct previous outputs. The stream only leaks forward, never backward.

Common CSPRNG algorithms include ChaCha20 (used in Linux's kernel CSPRNG since kernel 5.17), CTR_DRBG based on AES-256, and the Fortuna construction designed by Bruce Schneier and Niels Ferguson. These aren't academic curiosities — they're the actual algorithms running in your browser right now.

In JavaScript, the relevant API is crypto.getRandomValues(), part of the Web Crypto API. Call it with a typed array and it fills that array with CSPRNG output sourced from the operating system's entropy pool. There's no fallback to Math.random(), which is explicitly not cryptographically secure and should never be used for passwords, tokens, or anything security-adjacent.

What "Entropy" Means in Password Terms

Entropy, in the password context, is a measure of unpredictability — specifically, how many bits an attacker would need to brute-force guess a password if they know exactly how it was generated but not the actual output.

The formula is straightforward: if your character set has N possible characters and your password is L characters long, the entropy is L × log₂(N) bits.

A 12-character password using lowercase letters only (26 characters) gives you 12 × log₂(26) ≈ 12 × 4.7 ≈ 56.5 bits. Add uppercase (52 options): ≈ 68 bits. Add digits and symbols to reach a 95-character set: 12 × log₂(95) ≈ 12 × 6.57 ≈ 78.8 bits.

Those extra bits matter enormously. At 56 bits, a modern GPU cluster can crack a password in hours. At 78 bits, the same hardware would take longer than the age of the universe — even making optimistic assumptions about future computing advances.

This is why well-designed password generators don't just generate random characters — they let you tune the character set and length to hit a target entropy level. Some even display the entropy directly. When you see a generator show "~94 bits of entropy," that's not marketing fluff. It's a precise mathematical claim.

Why Browser-Based Generators Are Actually Trustworthy

The instinct to distrust browser-based password generators is understandable. You're typing sensitive information into a webpage, and web pages have historically been vectors for all kinds of mischief. But the architecture of a well-built browser password generator actually has significant security advantages over what most people imagine.

First, consider where the generation happens. A reputable browser-based generator runs entirely in your browser tab, using window.crypto.getRandomValues() to access the OS's CSPRNG. The generated password never leaves your device unless you copy it somewhere. No HTTP request is made. The server never sees it. You can verify this by disconnecting from the internet and watching the generator still work perfectly — a quick test worth doing.

Second, the cryptographic primitive is the same one your operating system uses for everything else security-critical. The browser is just providing a JavaScript API wrapper over the same entropy pool that generates your SSH keys, encrypts your disk, and authenticates your TLS connections. There's no "weaker" web version.

Third, modern browsers implement strict sandboxing. The password generator tab cannot read memory from other tabs. It cannot exfiltrate data to third-party scripts without those scripts being explicitly loaded on the page — which is why using a reputable generator with minimal third-party JavaScript matters. Opening the browser's developer tools and checking the Network tab while generating a password will show you exactly what, if anything, is being transmitted. Usually: nothing.

The real risk with browser generators isn't cryptographic weakness — it's social. Malicious generators that look legitimate, generators that transmit output to a logging server, or generators embedded in phishing pages. The solution is straightforward: use generators from trusted sources, check that the page works offline, and look at the source code if you're technically inclined.

The Bias Problem: How Generators Map Numbers to Characters

Here's a subtle bug that even experienced developers sometimes introduce. Suppose your character set has 90 characters and you want to pick one uniformly at random. You generate a random number between 0 and 255 (one byte from the CSPRNG), then take number % 90.

This produces biased output. The numbers 0–75 are slightly more likely to be selected than 76–89, because 256 is not evenly divisible by 90. The bias is small — about 0.4% — but in a cryptographic context, any non-uniform distribution is a correctness failure.

The correct approach is rejection sampling: generate a random number, check if it falls in a range that divides evenly into your character set size, and if not, discard it and try again. In practice, rejection is rare — you almost never need more than two attempts. The Web Crypto API specification explicitly warns about this, and well-written generators handle it correctly.

Another bias can creep in when generating passphrases from word lists. If your wordlist has 7,776 words (the standard Diceware list), you need to generate numbers in the range 0–7775. A naively written generator that uses a 16-bit random number (0–65535) and takes the modulo will have words at the beginning of the list appearing 0.001% more often than words at the end. Again, tiny — but the point is that secure random generation requires thinking carefully about every mapping step.

Diceware and the Human-Readable Alternative

Password characters are hard to remember and hard to type. Passphrases built from random words solve both problems without sacrificing security. The Diceware method — pick 6 words from a 7,776-word list — produces approximately 77.5 bits of entropy, comparable to a 13-character mixed-character password, but infinitely more memorable.

"correct horse battery staple" from the famous xkcd comic isn't just a joke — it's a real demonstration of this principle. Four words from a 7,776-word list gives 51.7 bits, which is decent but improvable. Five words gets you to 64.6 bits. Six words at 77.5 bits is the gold standard for most use cases.

Browser-based passphrase generators implement the same entropy pipeline as character generators, just with a final mapping step from numbers to words rather than numbers to characters. The CSPRNG underneath is identical.

What "Trustworthy" Looks Like in Practice

A genuinely trustworthy password generator has a short checklist: it uses crypto.getRandomValues() (not Math.random()), it handles the modulo bias problem correctly, it works offline, it loads minimal third-party scripts, and its source is auditable. Generators from reputable security companies, from password manager apps like Bitwarden or 1Password, or from established open-source projects generally meet all of these criteria.

The cryptography is solved. The algorithms have been audited to exhaustion. What you should actually spend time verifying is the implementation — the short stretch of code between "generate random bytes" and "display password to user" where biases can sneak in and where data can leak if someone was careless or malicious.

Understanding the science doesn't require trusting blindly. It gives you the tools to verify — and that's always the better position to be in.