Skip to content

Repository files navigation

passwordentropy.com

A password strength calculator that does things properly.

Most password strength meters are terrible. They check for a capital letter, a number, and call it a day. This one uses real cryptographic research, actual GPU benchmarks, and breach data to tell you how long your password would actually take to crack.

Sponsored by Upon: Digital Inheritance Vaults.

Why "P@ssw0rd!" Gets a Failing Grade

Traditional password meters reward complexity theater: swap an a for @, add a 1 at the end, and suddenly you're "strong." But attackers aren't stupid. They know about l33tspeak. They have dictionaries of common substitutions. "P@ssw0rd!" isn't 9 random characters drawn from 95 possibilities, it's a predictable mutation of the #4 most common password on the internet. In fact, it's been breached 120k times and is likely one of the first passwords an attacker will try!

How We Score Passwords

We combine three signals to estimate how quickly an attacker could crack your password:

  1. Pattern analysis: zxcvbn decomposes your password into dictionary words, keyboard patterns, and substitutions, then estimates how many guesses it would take.
  2. Breach data: we check Have I Been Pwned to see if your password has leaked, then apply a Zipf's law penalty based on how often it appears.
  3. Real hardware benchmarks: we use actual RTX 5090 hashcat speeds to show crack times across different hash algorithms and attacker resources.

The final entropy is the minimum of the pattern-based estimate and the breach-based estimate. A password in an attackers list from previous breaches is effectively worthless, no matter how random it looks.

What Is Password Entropy?

Entropy measures uncertainty, expressed as the number of guesses an attacker would need to find your password. We measure it in bits, where each bit doubles the search space:

Bits Possible Combinations Equivalent To
10 1,024 4-digit PIN with letters
20 ~1 million Weak password
40 ~1 trillion Moderate password
60 ~1 quintillion Strong password
80 ~1 septillion Very strong password

Mathematically, entropy is the base-2 logarithm of guesses needed, assuming an attacker tries passwords in optimal order. If you pick randomly from a character set of size N for L characters, entropy = L × log₂(N). A 10-character lowercase password has 10 × 4.7 ≈ 47 bits.

Humans don't pick randomly, though. We use words, patterns, and substitutions that drastically reduce the effective entropy. xkcd #936 illustrates this perfectly:

xkcd 936: Password Strength

The comic shows "Tr0ub4dor&3" at ~28 bits versus "correct horse battery staple" at ~44 bits. The complex-looking password is actually weaker. The number of guesses matters, not how "random" it looks to a human.

zxcvbn: Pattern Matching, Not Character Counting

We use zxcvbn-ts, a TypeScript port of Dropbox's zxcvbn library. Instead of the naive approach (entropy = log₂(charset_size) × length), zxcvbn models how attackers actually crack passwords:

  1. Dictionary attacks – Checks against common passwords, English words, names, and surnames
  2. Keyboard patterns – Recognizes "qwerty", "zxcvbn", and "123456"
  3. Repeated characters – "aaaaaaa" isn't 7 characters of entropy
  4. Sequences – "abcdef" and "13579" are predictable
  5. L33t substitutions – "@" for "a", "0" for "o", "$" for "s"
  6. Dates – Birthdays and anniversaries are common password components

zxcvbn estimates the number of guesses an attacker would need by finding the lowest-cost decomposition of your password into known patterns, which we can then convert into bits via entropy = log₂(guesses).

zxcvbn accurately estimates entropy for human-created passwords but is overly pessimistic about truly random ones. When no pattern matches, zxcvbn scores the remaining characters as a brute-force segment using a fixed cardinality of ~10 guesses per character — modeling an attacker who tries statistically likely characters first — rather than the full charset size. A 12-character random lowercase+digits password has a true entropy of 12 × log₂(36) ≈ 62 bits, but zxcvbn scores it as roughly log₂(10¹²) ≈ 36–40 bits. Similarly, "Hn@q8kKYN*" has ~60 bits of true entropy from its character set, yet zxcvbn estimates only ~33 bits.

For a strength meter this is the right direction to be wrong in: we'd much rather underestimate a random password than overestimate a human one. But keep it in mind when reading the site's numbers for generated passwords — the true crack time and cost are likely much higher than displayed.

Have I Been Pwned: When Your Password Is Already Public

Even a randomly-generated password becomes worthless if it's in a breach database. Attackers don't brute-force from scratch, they start with lists of known passwords, sorted by frequency. Your clever passphrase might be unique in your head, but if it leaked from Adobe in 2013, it's in every attacker's wordlist.

We check passwords against Have I Been Pwned's database of 850+ million compromised passwords without ever sending your password over the internet.

HIBP stores SHA-1 hashes of every leaked password in their database, which we query using a protocol called k-anonymity:

  1. We SHA-1 hash your password locally (e.g. password123 becomes CBFDAC6008F9CAB4083784CBD1874F76618D2A97)
  2. We send only the first 5 characters of the hash to HIBP (CBFDA)
  3. HIBP returns ~500 hash suffixes that match that prefix
  4. We check locally if our full hash suffix is in the list

The server never sees your password or even its full hash. The 5-character prefix matches ~500 other hashes, providing plausible deniability. We also use the Add-Padding: true header to prevent response length analysis.

Modeling Attacker Behavior with Zipf's Law

If your password appears in 10,000 breaches, how much does that actually hurt you?

Attackers don't try passwords randomly. They try them in order of popularity, and password frequency distributions follow Zipf's law, the same power law that governs word frequency in natural language. The most common password is tried first, the second most common second, and so on. A password that appears twice as often gets tried much earlier, not just a little earlier.

Research on password distributions ("A Large-Scale Study of Web Password Habits" and subsequent analysis) suggests that password frequency follows:

frequency(rank) = C / rank^s

We use the exponent s ≈ 0.78 for passwords as per the research papers. Inverting this formula lets us estimate rank from frequency:

rank = (C / frequency)^(1/s)
entropy = log₂(rank)

We use pessimistic parameters: C = 1,000,000, anchored to "password" appearing roughly 1 million times in breaches. This aligns with leaked datasets like RockYou and Collection #1, where the most common passwords appear millions of times.

Breach Count Estimated Rank Entropy (bits)
42,000,000 ~1 ~0
1,000,000 ~1 ~0
100,000 ~19 ~4.2
10,000 ~363 ~8.5
1,000 ~6,918 ~12.8
100 ~132,000 ~17
10 ~2,500,000 ~21.3
1 ~48,000,000 ~25.5

We also apply a hard cap of 25 bits for any breached password. Even if a password only appears once in a breach, the attacker's wordlist is only ~1 billion entries (log₂(1 billion) is ~30 bits of entropy) and we want to be conservative.

Hash Rate Benchmarks: RTX 5090 Numbers

The crack time table uses real-world benchmarks from hashcat running on an NVIDIA RTX 5090 (the current fastest consumer GPU for password cracking). Sources:

Fast Hashes (Don't Use These for Passwords)

Algorithm RTX 5090 Speed Notes
MD5 220.6 GH/s 220 billion attempts per second
SHA-1 70.2 GH/s Still catastrophically fast
SHA-512 10 GH/s Faster than you'd expect

These are message digests, not password hashes. They're designed to be fast, which is exactly wrong for password storage. If you see a site storing passwords as MD5... run. Even with salts, fast hashes remain unsafe because attackers can still test billions of guesses per second per account.

Key Stretching Functions (Use These)

KSFs are specifically designed to be slow, memory-hard, or both. We benchmark with production-realistic parameters:

Algorithm Parameters RTX 5090 Speed
PBKDF2 310,000 iterations (Django 4.x default) ~36 kH/s
bcrypt cost 10 (1,024 rounds) ~9.5 kH/s
scrypt N=16384, r=1, p=1 ~7.8 kH/s
Argon2id m=64MiB, t=3, p=1 (RFC 9106) ~2.2 kH/s

Argon2id is the current recommendation from the Password Hashing Competition. It's memory-hard, requiring 64MB of RAM per hash attempt, which makes GPU parallelization expensive. The parameters we use match the "first recommendation" from RFC 9106.

GPU Scaling

The table shows crack times across different attacker resources:

  • 1 GPU: Individual attacker or researcher
  • 10-100 GPUs: Small organization or dedicated attacker
  • 1,000-10,000 GPUs: Large corporation or criminal enterprise
  • 1,000,000 GPUs (Nation State): Theoretical upper bound rather than any known deployed system in 2025

The Math

For a given password, the time to crack is:

average_time = (2^entropy) / (2 × hash_rate × gpu_count)

We divide by 2 because on average, you'll find the password halfway through the search space.

Take a password with 62 bits of entropy. Here's how crack times differ based on how the site stores your password:

Storage Method 1 GPU 10k GPUs Nation State
MD5 4 months 18 minutes Instant
Argon2id 34M years 3.4k years 34 years

The same password, stored properly, goes from being crackable by a hobbyist to almost impossible to crack.

Estimating the Cost to Crack

Time tells you whether an attacker can crack your password; cost tells you whether it's worth it. The cost column estimates the total GPU rental bill:

gpu_hours = (2^entropy) / (2 × hash_rate × 3600)
cost = gpu_hours × price_per_gpu_hour

Note that cost is independent of how many GPUs the attacker uses: 10,000 GPUs finish 10,000× faster but cost the same in total. That's why the table has a single cost column rather than one per attacker scale.

We price GPU time at $0.20 per GPU-hour, deliberately pessimistic for the defender. On-demand RTX 5090 rentals run $0.40–0.67/hr, but spot/interruptible instances go as low as ~$0.10–0.20/hr, and attackers running their own farms pay closer to electricity cost. Consumer cards also beat AI-grade GPUs (H100 etc.) on hashes-per-dollar for cracking workloads, so cheap consumer rentals are the right lower bound.

Taking the same 62-bit entropy password from above:

Storage Method Total GPU Time Est. Cost
MD5 ~3,000 GPU-hours ~$600
Argon2id ~300B GPU-hours ~$60B

Stored as MD5, cracking it costs less than a phone. Stored as Argon2id, it costs more than most companies are worth.

"Protected For": How Long Until Cracking Becomes Affordable

Cracking hardware gets cheaper every year, so a password that costs $60B to crack today won't cost that forever. The advanced calculator lets you enter what your secret is worth to an attacker (their budget) alongside tunable hash parameters, and estimates how long until cracking your password costs less than that:

protected_years = halving_years × log₂(cost_today / attacker_budget)

We assume cracking cost per hash halves every 3 years. Real-world estimates of this rate:

  • GPU FLOP/s per dollar doubles every ~2.5 years (~2.95 years for top-end cards)
  • Flagship hashcat throughput per card (GTX 1080 → RTX 5090) doubled every ~2.75 years, with rental prices per GPU-hour roughly flat across generations
  • Koomey's law (computations per joule, the long-run floor set by electricity) slowed to a ~2.6-year doubling after Dennard scaling ended around 2005

All of these curves are decelerating, so a fixed 3-year halving remains pessimistic for the defender at long horizons. It's also why we cap the display at 100+ years: extrapolating exponential hardware improvement beyond a few decades is fiction.

For the 62-bit entropy Argon2id example against a $1M attacker budget: 3 × log₂($60B / $1M) ≈ 48 years of protection. (Hopefully longer!) The same password stored as MD5 is already crackable for pocket change today.

One caveat cuts the other way: the site's entropy comes from zxcvbn, which underestimates truly random passwords — a random 12-character lowercase+digits password scores ~36–40 bits on the site despite its true 62. Every underestimated bit halves the estimated cost (and shaves 3 years off the horizon), so for generated passwords the displayed "Protected For" is a heavy underestimate. Between the cheap GPU pricing, the aggressive halving rate, and zxcvbn's brute-force pessimism, a random password's real protection should comfortably exceed what we show.

The Passphrase Generator

The dice button beside the password field generates a passphrase of four random words with no separator, e.g. axlesalludedturkeysecond.

The Wordlist: Orchard Street Long

We use the Orchard Street Long wordlist in full: 17,576 words (26³) of 3-15 characters, worth 14.10 bits each. It's built for passphrases rather than as a general dictionary: words are chosen by frequency in Google Books Ngram and Wikipedia, with profanity, proper nouns, most homophones and British spellings removed, and no hyphens or apostrophes.

The list is also uniquely decodable: any concatenation of its words can only be split back apart one way, which is what makes joining with no separator safe. An ambiguous list would quietly lose entropy, because in + put and input are the same string and an attacker only has to guess it once. tests/generator.test.ts verifies this with the Sardinas-Patterson algorithm.

Randomness: Rejection Sampling, Not Modulo

Words are drawn with crypto.getRandomValues using rejection sampling rather than a modulo. 2^32 is not a multiple of 17,576, so % 17576 would make the first few thousand words very slightly more likely than the rest.

Length: Cap the Total, Not the Words

Words run from 3 to 15 characters, so an unconstrained four-word draw lands anywhere between 12 and 60 characters. A 43-character passphrase is much slower to type than a 30-character one without being any stronger, so draws over 36 characters (nine per word) are rejected. This pulls the 95th percentile down from 40 characters to 36 and removes the tail entirely.

Capping the total is far cheaper than dropping long words from the list:

Approach Words Remaining Cost at Four Words
Exclude every word over 9 characters 13,130 1.69 bits
Reject passphrases over 36 characters 17,576 0.26 bits

The cap only rejects draws that come out long overall, rather than every draw that happens to contain one long word. At any given ceiling, bounding the total is always at least as cheap as bounding each word.

The Entropy We Report

We know exactly how much randomness went into a generated passphrase, but we only ever report the lower of that figure and zxcvbn's independent score of the finished string. The generator never claims more strength than the calculator would give the same password typed in by hand.

To guarantee the two never contradict each other, candidates that zxcvbn rates at or above the entropy we put in are rejected and re-rolled. That isn't free: rejecting on a content-dependent test shrinks the keyspace to the accepted fraction, and an attacker who knows the algorithm only has to search that fraction. So the reported entropy is discounted by log₂(acceptance_rate) for both rejection tests together:

entropy = 4 × log₂(17,576) + log₂(acceptance_rate)
        = 56.4 - 0.86 = 55.5 bits

At four words, 65.8% of draws are both short enough and score low enough under zxcvbn. The discount uses a conservative floor of 55% rather than the measured rate, and the test suite asserts the real rate stays above it.

The Takeaways

  1. Use a password manager: Randomly generate a password for every service, and only need to remember your master password.
  2. Use long, high-entropy passwords: Four random dictionary words ("correct horse battery staple") have higher entropy than complex-looking mutations ("Tr0ub4dor&3") because attackers know about l33tspeak.
  3. Check your passwords against breaches: If it's leaked, it's worthless, no matter how random it looks.
  4. Use unique passwords everywhere: One breach compromises all accounts sharing that password.
  5. Demand proper password storage: Ensure services use a strongly configured key stretching function like Argon2id (ideally with PAKE such as OPAQUE and per-user salts). If a service stores your password with MD5 or SHA, they are failing you.
  6. 80+ bits of entropy remains out of reach, even for nation-states with theoretical million-GPU clusters. But don't forget rule #538:
    xkcd 538: Security

Acknowledgements

Built by Liam Gray and sponsored by Upon's Digital Inheritance Vaults.

The passphrase wordlist is derived from the Orchard Street Wordlists by Sam Schlinkert, used under CC BY-SA 4.0.

This project is source-available and hosted on Github Pages to allow anyone to inspect the underlying source code and verify the integrity of the deployed site.

About

Estimate password entropy and cracking times. Inspired by xkcd #936.

Topics

Resources

Stars

18 stars

Watchers

0 watching

Forks

Contributors

Languages