The Math Behind Password Security: Entropy, Brute Force, and Best Practices

The Math Behind Password Security: Entropy, Brute Force, and Best Practices

Password security advice has been notoriously wrong for decades. The old "must have uppercase, lowercase, number, and symbol" rules produce passwords like P@ssw0rd that are both easy to guess and annoying to remember. NIST finally updated its guidance in SP 800-63B, and the math supports a completely different approach. This guide covers the actual numbers behind password strength, modern cracking capabilities, and what the evidence says about best practices.

Generate cryptographically secure passwords with our Password Generator and compute hashes with our Hash Generator.

The Entropy Formula

Password entropy measures unpredictability in bits. The formula is:

Entropy = log2(N^L) = L × log2(N)

Where:
  N = size of the character set
  L = length of the password

This assumes randomly chosen characters—human-created "random" passwords have far less entropy than these calculations suggest, which is why password managers matter.

Specific Entropy Values

Password TypeN (charset)L (length)Entropy (bits)
8-char lowercase only26837.6 bits
8-char lowercase + uppercase52845.6 bits
8-char mixed case + digits62847.6 bits
8-char mixed + symbols (94 chars)94852.4 bits
12-char mixed + symbols941278.6 bits
16-char random printable9416104.9 bits
20-char random printable9420131.1 bits
// JavaScript entropy calculator
function calculateEntropy(length, charsetSize) {
  return length * Math.log2(charsetSize);
}

// Examples
calculateEntropy(8, 26);   // 37.6 bits (lowercase only)
calculateEntropy(8, 94);   // 52.4 bits (full ASCII printable)
calculateEntropy(16, 94);  // 104.9 bits
calculateEntropy(20, 94);  // 131.1 bits

// Required length for N bits of entropy
function requiredLength(targetBits, charsetSize) {
  return Math.ceil(targetBits / Math.log2(charsetSize));
}

requiredLength(128, 94);  // 20 characters
requiredLength(128, 62);  // 22 characters
requiredLength(128, 26);  // 28 characters

Real Cracking Speeds in 2026

Modern GPU clusters can attempt billions of password hashes per second. The specific throughput depends entirely on the hashing algorithm—this is why algorithm choice for password storage is critical:

AlgorithmRTX 4090 Speed8-char 94-charset Time
MD5~164 billion/sec~2.3 hours
SHA-1~57 billion/sec~6.6 hours
SHA-256~23 billion/sec~16.4 hours
bcrypt (cost 10)~184,000/sec~560 years
bcrypt (cost 12)~46,000/sec~2,200 years
scrypt (N=32768)~16,000/sec~6,400 years
Argon2id (t=3, m=64MB)~11,000/sec~9,300 years

The key insight: an 8-character password with all symbols is cracked in hours against MD5 but would take millennia against Argon2id. The hashing algorithm matters more than password complexity for stored passwords.

Time-to-Crack Table at Various Entropy Levels

Assuming a well-resourced attacker with 100 RTX 4090 GPUs attacking a bcrypt cost-12 hash:

EntropyPossible combinationsAverage crack time
40 bits~1 trillion~3 hours
52 bits~4.5 quadrillion~550 days
64 bits~18 quintillion~6,000 years
80 bits~1.2 × 10^24~390 million years
128 bits~3.4 × 10^38Longer than the universe's age

This shows that 64 bits of entropy (achievable with a 12-character random mixed-case password or a 5-word passphrase) is effectively uncrackable against bcrypt even with significant resources.

NIST SP 800-63B: The Evidence-Based Guidance

NIST's 2017 guidelines (updated in the 800-63B Digital Identity Guidelines) reversed decades of conventional wisdom. Key recommendations:

What NIST recommends:

  • Minimum 8-character length (15+ for admin accounts)
  • Support up to 64 characters (or more)
  • Allow all ASCII printable characters plus spaces
  • Check against known breached passwords (Have I Been Pwned API)
  • Use a salt unique to each password before hashing
  • Use a slow hashing function: bcrypt, scrypt, PBKDF2 (FIPS-approved), or Argon2

What NIST says to STOP doing:

  • Forced periodic password rotation (increases weak passwords—users just increment: Password1!Password2!)
  • Complexity rules (uppercase + lowercase + number + symbol requirements)
  • Password hints or security questions
  • SMS as the sole second factor (susceptible to SIM swapping)

Diceware: The Physics-Based Passphrase

Diceware passphrases use physical dice rolls to select words from a numbered wordlist, providing provable randomness without a computer:

// EFF Long Wordlist: 7,776 words (6^5 = 7776, one 5-dice roll per word)
// Entropy per word: log2(7776) ≈ 12.92 bits

// Passphrase entropy by word count:
// 3 words: 38.8 bits  (weak)
// 4 words: 51.7 bits  (moderate)
// 5 words: 64.6 bits  (strong — recommended minimum)
// 6 words: 77.5 bits  (very strong)
// 7 words: 90.4 bits  (excellent)

// Example 5-word passphrase: "correct horse battery staple union"
// Entropy: 64.6 bits (hard to crack, easy to remember)

The EFF wordlist is designed so that 3-letter hints uniquely identify each word, making passphrases easier to remember. A 5-word Diceware passphrase is both more memorable and more secure than a complex 8-character password.

Why Password Managers Solve Everything

The root problem with passwords is that humans cannot:

  1. Generate truly random strings
  2. Remember unique high-entropy strings for 100+ accounts
  3. Avoid reusing passwords across sites

Password managers solve all three. A password manager lets every account have a unique, 20-character random password without memorization. The only password that needs to be remembered is the manager's master password—where a 5+ word Diceware passphrase is ideal.

bcrypt vs scrypt vs Argon2 for Password Storage

bcrypt: The classic choice. Cost parameter is adjustable (doubles work per increment). Limitation: maximum 72-byte input (passwords >72 chars are truncated). Well-studied, available everywhere.

scrypt: Memory-hard (GPU cracking requires proportional RAM). Parameters: N (CPU/memory cost), r (block size), p (parallelism). Better than bcrypt for offline attack resistance.

Argon2id: Winner of the Password Hashing Competition (2015). Combines Argon2i (side-channel resistant) and Argon2d (GPU resistant). Three parameters: time cost (t), memory cost (m), parallelism (p). Current OWASP recommendation: t=3, m=64MB, p=4 for interactive logins.

// Node.js with Argon2 (argon2 npm package)
const argon2 = require('argon2');

// Hash a password
const hash = await argon2.hash(password, {
  type: argon2.argon2id,
  memoryCost: 65536,  // 64 MB in KB
  timeCost: 3,
  parallelism: 4
});
// "$argon2id$v=19$m=65536,t=3,p=4$..."

// Verify
const valid = await argon2.verify(hash, password);

// bcrypt (bcryptjs npm package - pure JS, or bcrypt for native)
const bcrypt = require('bcryptjs');
const saltRounds = 12; // ~300ms on modern hardware

const hash = await bcrypt.hash(password, saltRounds);
const valid = await bcrypt.compare(password, hash);

Rainbow Tables and Why Salting Is Non-Negotiable

A rainbow table is a precomputed table mapping hashes back to passwords. Without salting, if two users have the same password, their hashes are identical—and a single rainbow table entry reveals both.

A salt is a random value (16+ bytes) unique to each password, prepended before hashing. This forces an attacker to crack each password individually—precomputed tables are useless.

// Never do this - no salt!
const insecure = crypto.createHash('sha256').update(password).digest('hex');

// bcrypt and Argon2 automatically handle salting - the salt is embedded in the hash
// "$argon2id$v=19$m=65536,t=3,p=4$[SALT_HERE]$[HASH_HERE]"

// Manual salting (if using PBKDF2 for FIPS environments)
const salt = crypto.randomBytes(32);
const hash = await crypto.pbkdf2(password, salt, 600000, 32, 'sha256');
// Store both salt and hash

Related Tools

🔧 password generator 🔧 hash generator

Related Articles

JWT Demystified: Everything Developers Need to Know

Everything about JWTs: structure, signing algorithms, critical security vulnerabilities (alg:none, a…

The Complete Regex Cheat Sheet for Web Developers

Master regular expressions with this complete cheat sheet covering anchors, quantifiers, lookaheads,…