Why Math.random has no business generating a password
Math.random() is a fast, statistically-fine pseudorandom generator meant for animations and sampling — and its output is predictable if an attacker can observe enough of it, because JavaScript engines use PRNG algorithms with a knowable internal state, not cryptographic guarantees. Several real password generators built on it have been reverse-engineered for exactly this reason.
crypto.getRandomValues(), which this tool uses, is backed by the operating system's cryptographically secure random number generator — the same category of source used to generate encryption keys. That is the actual bar for anything meant to resist a determined attacker, not just look random to a human glancing at it.
Rejection sampling: the other place randomness quietly breaks
A common shortcut for picking a random character is randomByte % charsetLength. If the charset size does not divide 256 evenly — and almost none do — this systematically favors the characters at the low end of the set. A 62-character alphabet has this bias on every single draw.
This tool avoids it with rejection sampling: it draws a byte, and if that byte would fall in the biased leftover region, it throws it away and draws again. The result is that every character in the set has exactly equal probability, not approximately equal.
What entropy actually measures, and why length wins
Entropy in bits is length × log2(charset size) — the number of times you would have to halve the search space to find the password by guessing. A 12-character password using only lowercase letters has about 56 bits of entropy. Adding uppercase, digits and symbols to reach a 94-character set pushes that same 12 characters to about 78 bits — but going to 16 lowercase-only characters reaches about 75 bits, nearly the same gain from length alone.
The practical conclusion, and the reason most current guidance (including NIST's) emphasizes length over complexity rules: a longer password from a smaller set often beats a shorter one stuffed with symbol requirements, and it is also easier for a human to type correctly.
The crack-time estimate is a scenario, not a promise
The estimated time shown assumes an attacker with offline access to a properly-hashed password database, trying roughly 10 billion guesses per second — a realistic figure for cracking a fast hash like an unsalted MD5 or SHA-256 on modern GPU hardware. Against a service that rate-limits login attempts, or one using a slow, purpose-built hash like bcrypt or Argon2, real attacks are dramatically slower than this number suggests.
What the estimate is actually useful for is comparison: it tells you whether a password you generated here is in the "cracked before you finish reading this sentence" range or the "longer than the estimated age of the universe" range, which matters far more than the exact number of years in between.