What Is a Random Password?

Not all random passwords are equally random. The source of randomness matters enormously โ€” here's the difference between pseudo-random and cryptographically secure randomness, and why it determines whether a generator is safe to use.

What "Random" Actually Means

When security professionals say a password must be "random," they mean something specific: each character in the password must be independently selected with equal probability from the character set, using a source of randomness that an adversary cannot predict.

This is a stricter definition than everyday use of the word. It rules out:

True randomness for password generation requires a cryptographically secure source of entropy.

Pseudo-Random Number Generators (PRNGs)

A PRNG is a deterministic algorithm that takes a seed value and produces a sequence of numbers that look random but are completely determined by the seed. Given the same seed, a PRNG always produces the same sequence.

PRNGs are excellent for many purposes:

They are entirely unsuitable for cryptography or password generation. If an attacker can determine the seed โ€” by knowing the timestamp at generation time, by observing enough outputs to reconstruct the internal state, or by exploiting implementation details โ€” they can reproduce the exact password you generated.

Cryptographically Secure PRNGs (CSPRNGs)

A CSPRNG is a PRNG with additional properties that make it suitable for cryptographic use:

  1. Seeded with genuine entropy โ€” hardware noise, OS-level randomness, or similar sources that attackers cannot observe
  2. Computationally unpredictable โ€” even knowing the algorithm, no attacker can predict future outputs without knowing the secret internal state
  3. Backward-secure โ€” compromising future outputs does not allow reconstruction of past outputs

Operating systems provide CSPRNGs: /dev/urandom on Linux/macOS, CryptGenRandom on Windows, and the Web Crypto API in browsers. These are what reputable password generators use.

Why Math.random() Fails for Passwords

JavaScript's Math.random() is explicitly documented as not cryptographically secure in the ECMAScript specification. The V8 engine (Chrome, Node.js) uses an algorithm called xorshift128+, which is deterministic and has been shown to have predictable state with sufficient output observations.

Security risk: Any password generator that uses Math.random() without crypto.getRandomValues() is potentially insecure. The generated passwords may be predictable to an attacker who knows the generation algorithm and approximate timing.

How to check a generator: open its source code (View Source in the browser or check the GitHub repo) and search for Math.random. If it appears in password generation code without being supplemented by crypto.getRandomValues(), the generator is not cryptographically secure.

The Web Crypto API: The Right Tool

The Web Crypto API provides crypto.getRandomValues() โ€” a browser-native CSPRNG that draws entropy from the operating system's secure random source. It has been available in all major browsers since 2013 and is the correct tool for client-side password generation.

Example usage:

const buffer = new Uint8Array(32); // 32 bytes = 256 bits crypto.getRandomValues(buffer); // buffer now contains 32 cryptographically random bytes

This generator uses crypto.getRandomValues() exclusively. You can verify this by viewing the source of password-generator.js.

Rejection Sampling: Avoiding Modulo Bias

Even with a CSPRNG, naive character selection introduces a subtle bias. If you get a random byte (0โ€“255) and take it modulo a pool size (say, 62 for letters+numbers), the characters near the beginning of the pool are slightly more likely to be selected โ€” because 256 is not evenly divisible by 62.

The correct approach is rejection sampling: discard bytes that would introduce bias and draw a new byte. Specifically, discard any byte โ‰ฅ (256 โˆ’ 256 % pool_size) and draw again. This ensures the mapping from random bytes to characters is perfectly uniform.

This is a minor effect โ€” the bias is small โ€” but in a security-critical application, even small biases are worth eliminating. This generator uses rejection sampling on every character selection.

Why Human-Chosen Passwords Are Not Random

Humans are deeply bad at generating random sequences. Research consistently shows that people's attempts at "random" character sequences have measurable non-random properties:

This is not a cognitive failure โ€” it's a feature of the way human memory works. But it means that even a person trying to create a random password creates something with far less entropy than the theoretical maximum for that length and character set.

Cracking tools are trained on billions of real passwords and model these patterns. A human's "random" password is likely to fall early in a dictionary attack, long before a brute-force attack would even begin.

Frequently Asked Questions

One where each character is independently selected with equal probability from a defined character set, using a cryptographically secure random number generator (CSPRNG) seeded with genuine, unpredictable entropy. The key property is that no adversary can predict or reproduce the output.

No. The ECMAScript specification explicitly states that Math.random() does not provide cryptographically secure random numbers. Major implementations (V8, SpiderMonkey) use algorithms like xorshift128+ which have predictable internal state. Always use crypto.getRandomValues() for password generation.

View the page source (Ctrl+U / Cmd+U) or inspect the JavaScript files. Search for Math.random โ€” if it's used in password generation without crypto.getRandomValues(), the generator is not secure. Also check that passwords are generated client-side (no network requests in the Network tab when clicking "Generate").

Generate a cryptographically random password

This generator uses crypto.getRandomValues() with rejection sampling โ€” verifiable in the source.

Generate a random password โ†’

Related Guides