Two passwords, identical to the character — say Tr0ub4dor&3 — can have wildly different fates. One gets cracked before you finish reading this sentence. The other survives a nation-state’s cracking rig for the heat death of the account. The difference has almost nothing to do with the password itself and almost everything to do with two decisions: how the password was chosen, and how it was stored. The first decides its entropy. The second decides how fast an attacker can burn through the guesses. Get either wrong and the other barely matters. This piece walks through the math, the tooling, and the reason the whole model is being quietly retired in favor of passkeys.
Entropy, Honestly
Everyone quotes password “entropy” as if it were a strength meter. It is a useful number, but only if you are precise about which entropy you mean and what assumption it rides on.
Shannon entropy is a measure of average unpredictability across a distribution. For a password drawn uniformly at random from an alphabet of size N at length L, it is clean and exact:
H = L * log2(N) bits, for a UNIFORMLY RANDOM password
Search space = N^L
Guesses for ~50% success ~= 2^(H-1)
N = charset size, L = length
------------------------------------------------------------
8 random lowercase : N=26, L=8 -> 8 * log2(26) ~= 37.6 bits
8 all-ASCII printable: N=95, L=8 -> 8 * log2(95) ~= 52.6 bits
12 all-ASCII : N=95, L=12 -> 12 * log2(95) ~= 78.8 bits
16 random lowercase : N=26, L=16 -> 16 * log2(26) ~= 75.2 bits
------------------------------------------------------------
Look at the last two rows. A 16-character all-lowercase string (a boring charset, but long) reaches ~75 bits and beats an 8-character password using the full printable ASCII set with its symbols and mixed case (~53 bits). That is the entire argument for length over complexity in one comparison. It falls straight out of the formula: L is the exponent in NL, so adding characters grows the search space geometrically, while enriching the charset only grows the base linearly. Length wins because length is exponentiated.
The catch that changes everything
Every number above assumes the password was drawn uniformly at random. Humans do not do that. We pick Summer2026! and P@ssw0rd123!, we capitalize the first letter and put the digit and symbol at the end, we substitute @ for a. That structure is exactly what an attacker models.
This is where guessing entropy — the metric that actually matters to an attacker — diverges from Shannon entropy. Guessing entropy is framed as the number of guesses needed to reach roughly 50% success. For a truly random n-bit secret, that is about 2n-1 guesses. But for a human-chosen password, the attacker does not iterate the full space; they iterate a ranked space of likely candidates first. P@ssw0rd123! has ~52 theoretical bits and perhaps a handful of bits of real guessing entropy, because it sits near the top of every rules-based wordlist on Earth.
Charsetlength entropy is an upper bound for random passwords only. For human-chosen passwords it is a fiction — it overstates strength by orders of magnitude, because it assumes an attacker with no idea how people behave.
NIST learned this the hard way. Its original 2004 SP 800-63 tried to approximate the entropy of human-generated passwords — famously pegging an eight-character human-selected password at roughly 18 bits — while openly conceding that little real-world data existed to justify the estimate. Later revisions abandoned that entropy-scoring approach as misleading, because it dressed up a guess about human behavior as a precise measurement. The replacement philosophy is simpler and more honest: require length, and screen against what people actually pick.
What NIST Now Says (SP 800-63B-4)
The final revision of the authentication guidelines, SP 800-63B-4, was published in July 2025 after a multi-year process spanning two public drafts. If you build authentication systems, Section 3.1.1.2 is the part to internalize. The normative requirements, at the SHALL/SHOULD level:
- Minimum 15 characters when a password is the sole authenticator (SHALL).
- Minimum 8 characters when the password is one factor within MFA (SHALL, as a floor; 15+ still preferred).
- Permit at least 64 characters maximum length (SHOULD).
- Compare against a blocklist of commonly-used, expected, or compromised passwords, and reject matches (SHALL).
- No composition rules — verifiers SHALL NOT impose mixtures of character types (no “must contain an uppercase, a digit, and a symbol”).
- No periodic rotation — verifiers SHALL NOT require routine password changes, but SHALL force a change on evidence of compromise.
Each of these is a direct consequence of the entropy reasoning above. The 15-character floor targets length, the true source of strength. Dropping composition rules acknowledges that forced complexity just pushes users toward predictable patterns (the P@ssw0rd1! phenomenon) that add theoretical bits but little guessing entropy. Dropping mandatory rotation acknowledges that forced 90-day changes produce Summer2026 then Autumn2026 — predictable increments an attacker anticipates. And the blocklist is the practical replacement for the entropy metric: instead of estimating whether a password is weak, just check whether it is already known to be.
How Cracking Actually Works
An attacker with a stolen hash database does not sit at a login form. They take the hashes offline and feed them to a cracker — overwhelmingly hashcat, a GPU-accelerated tool supporting 300+ hash types (MD5, SHA-1, NTLM, bcrypt, WPA, and on and on) that can test billions of candidate hashes per second on modern hardware. The workflow is: hash each guess with the same algorithm the database uses, and compare against the stolen hashes.
The naive strength estimate is a division:
time_to_exhaust = N^L / guesses_per_second
time_to_50pct = time_to_exhaust / 2
Both inputs must be STATED, never assumed:
* guesses_per_second depends on the HASH algorithm,
the HARDWARE (one GPU vs. a cloud fleet), and the ATTACK MODE.
* N^L assumes uniform randomness; real attacks use
dictionary + rules and never traverse the full space.
This is why “it would take 3 trillion years to crack” headlines are close to meaningless. They quietly assume (a) a specific slow hash, (b) modest hardware, and (c) that the attacker brute-forces the entire uniform space. Against a human password, assumption (c) is simply false. No competent attacker walks NL. They rank candidates and try the likely ones first.
The attack modes that matter
hashcat’s real modes map directly to how humans build passwords:
- Dictionary / straight (
-a 0) — run a wordlist (leaked-password corpora,rockyou.txt, language dictionaries) directly against the hashes. - Combinator (
-a 1) — concatenate every word in one list with every word in another (correct+horse→correcthorse). - Brute-force and mask (
-a 3) — a mask is a targeted subset of brute force that encodes known structure.?u?l?l?l?l?d?dmeans “uppercase, four lowercase, two digits” — precisely the shape ofAdmin24-style passwords, and vastly smaller than the full space. - Hybrid (
-a 6/-a 7) — append or prepend a brute-forced mask to each dictionary word, e.g. every word plus?d?d?d?dto catchpassword2026.
On top of these sits the rule-based attack, which hashcat’s own wiki calls “the most flexible, accurate and efficient attack.” Rules are a mini programming language of mutations applied to each wordlist entry: capitalize the first letter, leetspeak-substitute a→@ and o→0, append !, duplicate, reverse. A single 100k-word list expanded by a good rule set becomes tens of millions of high-probability candidates — and it lands on P@ssw0rd123! almost immediately. Real cracking is dictionary + rules, not brute force. That is the whole reason human-chosen “complexity” fails: the attacker’s rules encode the exact transformations humans use to satisfy complexity requirements.
The Hash Is the Whole Ballgame
Now the single biggest lever. The same password, with the same entropy, is either trivial or intractable to crack depending purely on how it was stored. Storage algorithms fall into two camps.
Fast hashes — MD5, SHA-1, NTLM, raw SHA-256 — were designed to be fast. That is a virtue for checksums and a catastrophe for password storage, because “fast to compute” means “fast to guess.” On a single modern GPU these fall to tens or hundreds of billions of guesses per second.
Slow KDFs — bcrypt, scrypt, Argon2id — are deliberately expensive. They have a tunable work factor that makes each single hash slow enough to be imperceptible to a legitimate user (a few tens of milliseconds at login) but ruinous to an attacker doing it billions of times. Throughput drops by many orders of magnitude, into the thousands of guesses per second per GPU.
To make the gap concrete — and read this as an order-of-magnitude illustration, not a benchmark to memorize — the widely-cited hashcat v6.2.6 benchmark on a single NVIDIA RTX 4090 reports these throughputs for fast hashes, alongside bcrypt at a realistic cost factor:
Same GPU, same password, different storage (hashcat v6.2.6, RTX 4090):
MD5 ~ 164,100 MH/s (~1.6 x 10^11 guesses/sec)
SHA-1 ~ 50,600 MH/s
SHA-256 ~ 22,000 MH/s
bcrypt ~ 184 kH/s (cost factor 5, per hashcat -b)
bcrypt ~ a few thousand H/s at OWASP-recommended cost 10+
At a production cost factor, MD5 is on the order of TENS OF MILLIONS
of times faster to attack than bcrypt on the SAME hardware.
The password did not change; only the storage did.
Read those numbers as “hundreds of billions per second vs. thousands per second,” not as gospel figures — throughput swings with GPU, driver, and hashcat version, and each bcrypt cost increment halves the attacker’s rate. The point is the many-orders-of-magnitude chasm. A fast-hashed 8-character password falls in a practical window on a single GPU. The identical password under a properly-tuned slow KDF does not.
Why memory-hardness beats GPUs
bcrypt’s work factor burns CPU time, which helps — but a GPU has thousands of cores, so it still parallelizes bcrypt reasonably well. scrypt and Argon2 add a second dimension: memory-hardness. Each guess must allocate a large block of memory. GPUs and ASICs have enormous compute but comparatively little high-bandwidth memory per core, so when every guess demands megabytes of RAM, the attacker’s massive parallelism collapses — there simply isn’t enough memory to run thousands of guesses at once. That is the structural reason Argon2id is the current first choice.
bcrypt (1999, Blowfish-based) | Argon2id (PHC-2015 winner, RFC 9106)
------------------------------------|-------------------------------------
Tunable: work/cost factor (CPU) | Tunable: memory (m), time (t),
NOT memory-hard -> GPU-friendlier | parallelism (p) -> MEMORY-HARD
Truncates input at 72 bytes | No practical length truncation
OWASP legacy: cost >= 10 | OWASP first choice:
| m=19456 KiB (19 MiB), t=2, p=1
------------------------------------|-------------------------------------
bcrypt 72-byte GOTCHA: input beyond 72 bytes is silently cut, so two long
passphrases sharing their first 72 bytes collide. Pre-hash if you must.
Migration: bcrypt is legacy/compatibility; new systems default to Argon2id
(or scrypt N=2^17, r=8, p=1 if Argon2 is unavailable; PBKDF2-HMAC-SHA256
at 600,000 iterations for FIPS-140 environments).
Provenance matters here. Argon2 won the 2015 Password Hashing Competition (Biryukov, Dinu, Khovratovich) and is specified in RFC 9106 (September 2021), which recommends the id variant when you are unsure or when side-channel resistance matters. OWASP’s Password Storage Cheat Sheet ranks Argon2id first, scrypt as fallback, and bcrypt for legacy compatibility only.
Reuse, Stuffing, and the Breach Economy
Everything above concerns cracking one hash from one breach. The reason a single crack becomes a fleet-wide compromise is password reuse. The 2025 Verizon DBIR, drawing on infostealer-infection data, found that in the median case only 49% of a user’s passwords across services were distinct — meaning the typical infected user reuses passwords across roughly half their accounts.
That reuse is the fuel for credential stuffing: take a username/password pair recovered from breach A and replay it automatically against sites B, C, and D. No cryptography is broken; the credential is simply valid in more than one place. The DBIR’s 2025 numbers show how central this has become:
- Compromised credentials were the initial access vector in 22% of breaches — among the leading methods.
- In SSO-provider log analysis, credential stuffing accounted for roughly 19% of all authentication attempts on a median daily basis.
The named 2024–2025 incidents make the mechanism vivid. Roku disclosed two 2024 waves (~15,000 then ~576,000 accounts) accessed purely with credentials reused from unrelated breaches. DraftKings suffered automated account takeovers in October 2024. The North Face confirmed a credential-stuffing attack on April 23, 2025 — VF Corporation’s fourth such incident since 2020. And in late March 2025, five Australian superannuation funds (AustralianSuper, Rest, Hostplus, Australian Retirement Trust, Insignia) were stuffed with combolists, with four AustralianSuper members losing a combined AUD 500,000. In none of these was a site “hacked” cryptographically. Reused passwords from other breaches were simply replayed.
The defensive counter-move: blocklists without leaking the password
NIST tells you to screen against compromised passwords. The obvious problem: how do you check a password against a corpus of billions of leaked ones without transmitting the password? Have I Been Pwned’s Pwned Passwords solves this with a k-anonymity range query. Here is the exact mechanic:
1. Hash the candidate password locally with SHA-1:
"P@ssw0rd" -> SHA-1 = 21BD1... (40 hex chars)
2. Send ONLY the first 5 hex characters (the prefix) to the range API:
GET https://api.pwnedpasswords.com/range/21BD1
3. Server returns EVERY stored hash SUFFIX sharing that prefix,
each with a breach count, e.g.:
0018A45C4D1DEF81644B54AB7F969B88D65:1
00D4F6E8FA6EECAD2A3AA415EEC418D38EC:2
... (a few hundred rows)
4. Client compares its OWN suffix against the returned list, LOCALLY.
Match -> the password is in a breach corpus. Reject it.
The full password and full hash never leave the device. There are 165 possible prefix buckets (just over a million), and on the current dataset a 5-character prefix returns on average about 478 suffixes — enough anonymity set to hide which one you actually queried, few enough to transfer instantly. This is how a NIST-style blocklist check runs client-side without ever exposing the secret. Both SHA-1 and NTLM prefixes are supported, since the point here is not cryptographic strength but a stable, uniformly-distributed bucketing function.
The Passkey Endgame
Everything to this point is damage control. Long passphrases raise entropy; slow KDFs raise the cost of cracking; blocklists catch the known-bad; k-anonymity lets you screen privately. All of it manages a shared secret that can still, in principle, be stolen, cracked, or replayed. Passkeys remove the shared secret entirely.
Passkeys are built on the FIDO2 and W3C WebAuthn standards, using asymmetric public-key cryptography. At registration, the authenticator (your phone, laptop, or a hardware key) generates a keypair. The private key never leaves the authenticator. The server stores only the public key. At login, the server sends a random challenge; the authenticator signs it and returns the signature; the server verifies it against the stored public key.
Two properties follow directly, and they demolish the threat models above:
- Nothing to crack or stuff. The server database holds public keys. A breach of it yields nothing an attacker can replay — public keys are, by design, public. There is no hash to feed hashcat and no credential to reuse on another site.
- Phishing-resistant by construction. Each authentication is cryptographically bound to the requesting origin (domain). A signature produced for
bank.comis worthless atbank-login.evil.com, because the origin is part of what gets signed. There is no secret for a user to be tricked into typing into the wrong box.
This is not a fringe position. CISA’s “Implementing Phishing-Resistant MFA” fact sheet names FIDO/WebAuthn and PKI (PIV/CAC) as the two gold-standard implementations, and explicitly warns that OTP, SMS, and push-based MFA remain vulnerable to phishing, SIM-swap, SS7 attacks, and prompt bombing. Adoption is moving: a 2024 FIDO Alliance survey found 53% of people had enabled passkeys on at least one account, with 22% enabling them everywhere possible.
Device-bound vs. synced
One distinction worth knowing. Device-bound passkeys are non-exportable and hardware-stored (a security key, or a platform TPM/secure enclave) — highest assurance, because the private key physically cannot leave the device. Synced passkeys are end-to-end encrypted and replicated across your devices through a provider (Apple, Google, a password manager) for convenience and recoverability. Both meet the phishing-resistant definition; device-bound trades convenience for a higher assurance bar. For most consumer accounts, synced passkeys are the right default; for privileged or high-value accounts, prefer device-bound.
Paste a candidate password to see its estimated entropy, how it fares against dictionary-plus-rules attacks, and whether it appears in breach corpora via a privacy-preserving k-anonymity lookup.
Key Takeaways
- Length beats complexity, and the math says why: in NL, length is the exponent. A long lowercase passphrase out-hardens a short symbol-salad. Prefer 15+ character passphrases, per NIST SP 800-63B-4.
- Entropy is an upper bound, not a promise: charsetlength only equals real strength for uniformly random passwords. Human choices have far lower guessing entropy — which is exactly why NIST dropped the old entropy metric for length plus blocklists.
- The hash decides the economics: the same password is trivial under MD5/SHA-1/NTLM and intractable under Argon2id. Storage choice can swing crack cost by many orders of magnitude on identical hardware.
- Build with slow, memory-hard KDFs: Argon2id first (OWASP: m=19456, t=2, p=1), scrypt as fallback, bcrypt (cost ≥ 10) only for legacy — and mind bcrypt’s silent 72-byte truncation.
- Reuse is the multiplier: credential stuffing was a leading initial-access vector in the 2025 DBIR because the median user reuses passwords across half their accounts. Screen new passwords against HIBP via k-anonymity — only a 5-char SHA-1 prefix ever leaves the device.
- Passkeys change the board: no shared secret means nothing to crack, phish, or stuff. Where WebAuthn/FIDO2 is offered, enable it; the three levers are length, slow hashing, and passkeys.
References
- NIST SP 800-63B-4, Digital Identity Guidelines: Authentication and Authenticator Management (final)
- NIST SP 800-63B-4 (HTML)
- NIST Revises Digital Identity Guidelines | SP 800-63-4 (published July 2025)
- OWASP Password Storage Cheat Sheet
- RFC 9106: Argon2 Memory-Hard Function for Password Hashing
- P-H-C/phc-winner-argon2 (2015 Password Hashing Competition winner)
- hashcat wiki (supported hash types, attack modes, rule-based attack)
- hashcat v6.2.6 benchmark on the NVIDIA RTX 4090 (Chick3nman gist)
- Troy Hunt: Understanding Have I Been Pwned’s Use of SHA-1 and k-Anonymity
- Have I Been Pwned: API Documentation (Pwned Passwords range query)
- Verizon 2025 Data Breach Investigations Report
- Verizon: Additional 2025 DBIR research on credential stuffing
- Roku says 576,000 user accounts hacked after second security incident (TechCrunch)
- The North Face warns customers of April 2025 credential stuffing attack (BleepingComputer)
- Australian pension funds hit by wave of credential stuffing attacks (BleepingComputer)
- CISA: Implementing Phishing-Resistant MFA (fact sheet)
- FIDO Alliance: World Password Day 2024 Consumer Password & Passkey Trends
- Password strength (Wikipedia) — NIST 2004 ~18-bit entropy estimate