How long should a password be: entropy, average guesses, and guesses per second

· 7 min read · password entropy security · 简体中文

“How strong is this password” is arithmetic, but the input to that arithmetic is how the string was chosen, not what it looks like. The same characters sampled by a machine and invented by you differ by orders of magnitude while looking identical on screen. How the string was sampled, and how fast an attacker can test one candidate, are the two inputs that decide everything; the arithmetic between them is short, and it cannot see reuse, phishing, or how the site stored the secret in the first place.

Bits come from the sampler only

For a generated password there is one calculation:

bits = length × log2(pool)
Pool Bits per item
26 lowercase letters 4.70
62 letters plus digits 5.95
94 printable ASCII 6.55
7776-word EFF list, per word 12.93

So 20 characters from the full printable pool is 131 bits, while four dice words are only 51.7 bits. The phrase that matters is “pool”: it describes the sampler, not the string. Password123! uses four character classes and 12 positions, so the 94-pool formula prints 78.7 bits — but it was not drawn uniformly from 94 symbols; it is a dictionary word with a suffix, and any wordlist-plus-common-transformations enumeration puts it near the front. The same formula on a password you typed is a ceiling, not a measurement. A v4 UUID is the opposite case: the format fixes 122 of its 128 bits as random, so the count holds whatever the value looks like, and the UUID generator prints it next to every value made.

Guessers stop at the average, so half the space

Exhaustive search needs, on average, half the space, which is why every number here uses 2^(bits-1) ÷ rate. That missing bit never changes a conclusion, but noticing whether someone quoted “worst case” or “average” is the first test of their arithmetic.

Guesses per second is what spreads the table

Counts of guesses are one thing; speed is another, and speed spans nine orders of magnitude:

  • 100/s — a login form that rate-limits, locks accounts and never leaks a hash (one retry per second with a five-minute lockout is slower still).
  • 10⁴/s — a site that stored passwords with bcrypt or Argon2id and then got dumped: those hashes are deliberately expensive, and this number can be far lower.
  • 10¹¹/s — a GPU farm chewing an unsalted fast-hash file (NTLM, or MD5/SHA used as a password hash). This is the number people mean when they say “seconds”.

Dividing 2^(bits-1) by those rates gives the average times (rounded):

Password shape Bits 100/s 10⁴/s 10¹¹/s
8 lowercase 37.6 33 years 121 days 1 second
12 hex characters 48.0 45,000 years 446 years 23 minutes
4 dice words 51.7 580,000 years 5,800 years 5.1 hours
8 printable ASCII 52.4 970,000 years 9,700 years 8.5 hours
12 letters + digits 71.5 5.1×10¹¹ years 5.1 billion years 512 years
6 dice words 77.5 3.5×10¹³ years 350 billion years 35,000 years
12 printable ASCII 78.7 7.5×10¹³ years 755 billion years 75,000 years
20 printable ASCII 131.1 meaningless meaningless 4.6×10²⁰ years

Read it as: don’t ask “how many characters”, ask “how long at which rate”. 50 bits is centuries at a throttled login form and minutes against a dumped fast-hash file — the difference is not the password, it is how that site stores it. A working target today is 70-80 bits or more, because you do not control the storage column and must assume the worst one.

Why complexity rules make things weaker

“Must contain one uppercase, one digit, one symbol” adds no entropy: it only removes some candidates from the pool. The loss comes from what it pushes you towards — capitalise the first letter, append 123!, use Spring2024#. The more specific the rules, the harder people squeeze into patterns, and enumerators try those patterns first.

Length, on the other hand, nearly always wins: one extra character on a 94-pool is +6.55 bits, two are +13.1. On a site capped at 12 characters, stuffing in symbol classes trades length for rule-points. There are only two real routes to strength: longer, or genuinely random.

A generator has to get three things right

  1. Randomness from the operating system. crypto.getRandomValues is the browser’s window onto that entropy source. Math.random is a clock-seeded xorshift: a few of its outputs are enough to recover internal state and predict everything after — so “generated” becomes “guessable”. When the browser refuses to give a cryptographic value, the correct behaviour is to refuse to generate, not to fall back to something quieter and worse.
  2. Discard the remainder, do not fold it in. value % 62 is not uniform: 4,294,967,296 is not divisible by 62, so the first characters of the alphabet inherit the remainder and appear slightly more often. The fix is to redraw whenever the value lands in that tail (rejection sampling). The skew is small, but small skew is exactly what a generator’s statistical fingerprint is made of. The password generator uses rejection sampling at every step, including the shuffle.
  3. Shuffle after applying constraints. Placing “one uppercase, one digit, one symbol” at the front makes every password start the same way. Draw the characters first, then Fisher–Yates shuffle the positions (again with rejection sampling).

A counter-intuitive corollary: generating 50 candidates and picking the “best” is meaningless — each came from the same sampler and they are equally strong. Use the first. If a site rejects it, type the rejected characters into the never-use box and regenerate; editing by hand is precisely where patterns are born.

Four things the arithmetic never covers

  • Reuse. One dump chains all your accounts. However high the bits, reusing once drops them to zero — this, not short passwords, is why real accounts get taken over.
  • How the site stores it. Unsalted MD5/SHA, or bcrypt with a low cost factor, moves you into the worst column of the table above. You cannot control this; you can only prefer sites using Argon2id or bcrypt.
  • Phishing and keyloggers. When a password is handed over by its owner, bit count is irrelevant. That is the argument for passkeys and second factors.
  • Clipboard and screen. Copy-paste is a real, small exposure — the clipboard is shared with every program on the machine — and the generator says so after you copy rather than pretending otherwise. Nothing is persisted: no storage is written and nothing you type goes out in a request, so it never leaves this device. Candidates do stay on screen until you clear or regenerate, which is deliberate, but the screen is then the storage: put the one you use into your manager, then regenerate.

Can I trust the site’s strength meter? Not alone. It can only see the string you typed, and cannot tell a random draw from an invented one; many jump to “strong” the moment you add !. A number beats a colour bar, and knowing the sampler beats the number.

So how many characters? Split by scenario: only in front of a throttled login form, almost anything survives; assuming a dump of a slow-hash store, 60 bits starts to mean something; assuming bad storage, you want 80+. For a password-manager master password, 6-8 random words is the usual advice — it is the one password you must remember, and the one worth assuming the worst column for.

Does removing look-alike characters weaken it? Slightly and cheaply. The generator’s ambiguous set is 10 characters (i I l 1 L o O 0 | and backtick), so the printable pool shrinks from 94 to 84: 6.55 → 6.39 bits per character, about 2 bits lost over 12 positions. Worth it if you will ever type the password somewhere awkward; not worth it if a manager fills it.

Why is “at least one of each class” optional? It is an escape hatch for sites that demand it, not a strength feature. A 20-character draw from the full pool almost always contains every class anyway, so forcing the arrangement takes entropy away from a password that had it already.

Support on PayPal