How to generate a cryptographically secure password (and why most tools don't) Written on . Posted in Tutorials.
Math.random() is not secure — and many password generators use it
Math.random() in JavaScript is a pseudo-random number generator (PRNG). Its output is deterministic — given the same seed, it produces the same sequence. Attackers who can observe a few outputs can sometimes predict future ones. This makes any password generated with Math.random() theoretically predictable.
What "cryptographically secure" actually means
A cryptographically secure pseudo-random number generator (CSPRNG) is designed so that knowing the output reveals nothing about past or future values. In browsers, this is window.crypto.getRandomValues(). In Node.js: crypto.randomBytes(). In Python: secrets.token_bytes().
// Wrong — predictable
const bad = () => Math.floor(Math.random() * 94) + 33;
// Correct — cryptographically secure
function secureRandom(max) {
const array = new Uint32Array(1);
window.crypto.getRandomValues(array);
return array[0] % max;
}
What makes a strong password
| Length | Character set | Entropy | Time to crack (GPU) |
|---|---|---|---|
| 8 | lowercase | 37 bits | minutes |
| 12 | lower + upper + digits | 71 bits | centuries |
| 16 | all printable ASCII | 105 bits | heat death of universe |
The practical recommendation: 16+ characters, all character types, generated by a CSPRNG. Length matters more than complexity.
Passphrase vs password
A 4-word passphrase (correct-horse-battery-staple) has ~51 bits of entropy and is far easier to type and remember than Xk9#mP2!. For human-remembered passwords, use passphrases. For credentials stored in a password manager, use a 20-character random string.
Generate a secure password now
Our password generator uses window.crypto.getRandomValues() and runs entirely in your browser. Your password is never sent anywhere.