How secure random password generation works
The generator uses crypto.getRandomValues() — the Web Crypto API's CSPRNG (Cryptographically Secure Pseudo-Random Number Generator). Unlike Math.random(), which is deterministic and predictable from its seed, crypto.getRandomValues() is seeded from the operating system's entropy pool (hardware timing events, mouse movements, network activity). It cannot be predicted from its outputs.
The generation process:
- Build a character set from your selected options (uppercase, lowercase, digits, symbols)
- Fill a byte array of the requested length with secure random bytes
- Map each byte to a character:
charset[byte % charset.length]
This simple process is secure because the byte distribution is uniform and unpredictable. The modulo operation introduces a tiny bias when charset.length doesn't divide 256 evenly, but for practical password lengths and charset sizes, this bias is negligible (< 0.4%).
Password entropy: the only metric that matters
Entropy (in bits) measures the unpredictability of a password. Each additional bit doubles the number of possible passwords:
| Entropy | Passwords | Example | |---------|-----------|---------| | 28 bits | ~268 million | 5 lowercase chars | | 40 bits | ~1 trillion | 8 lowercase chars | | 60 bits | ~1 quintillion | 10 mixed alphanumeric | | 80 bits | ~1.2 × 10²⁴ | 13 full charset | | 100 bits | ~1.3 × 10³⁰ | 17 full charset |
The formula: Entropy = length × log₂(charset size)
A 16-character password using all four character types (charset size: 94) produces entropy = 16 × log₂(94) ≈ 104 bits. This is completely infeasible to brute-force — even at a billion billion guesses per second, it would take longer than the age of the universe.
Crack time assumptions
The "time to crack" estimate assumes 10 billion guesses per second — a realistic estimate for a dedicated GPU cluster attacking a fast hash (MD5, NTLM, or similar). Against stronger hashing algorithms used by modern systems:
- bcrypt (cost 12): ~100 guesses/second — crack times become 10⁸× longer
- Argon2id (strong): ~1,000 guesses/second — even more resistant
The displayed crack time is therefore a worst-case estimate for the weakest possible storage. Against bcrypt, even a 40-bit password would take years. The right defense is both a strong password AND proper hashing on the server side.
Character types and their contribution to entropy
| Type | Characters | Charset size | log₂ | |------|------------|--------------|------| | Lowercase only | a–z | 26 | 4.7 | | + Uppercase | A–Za–z | 52 | 5.7 | | + Digits | A–Za–z0–9 | 62 | 5.95 | | + Symbols | All printable | 94 | 6.55 |
Adding symbols to a 16-character password increases entropy from 95 bits to 104 bits — useful, but less impactful than simply adding more length. Length is the dominant factor. A 20-character all-lowercase password has higher entropy than a 12-character full-charset password.
Passphrases vs random character passwords
A passphrase like correct-horse-battery-staple (4 random words from a 7,776-word list) has ~52 bits of entropy. A 16-character random password from a 94-character charset has ~104 bits. The random password wins on entropy per keystroke.
However, passphrases have a usability advantage: they're easier to memorize and type without a password manager. For accounts you type manually, a 5–6 word passphrase from a large wordlist is a good alternative.
For everything else — use a password manager and let it generate 20+ character random passwords.
Storing passwords safely
A strong generated password is only as secure as where you store it. The best practices:
- Use a password manager (Bitwarden, 1Password, Keychain) — the only scalable solution
- Never store passwords in plain text files, notes apps, or spreadsheets
- Never reuse passwords across sites — one breach exposes all accounts
- Enable two-factor authentication on accounts where it's offered