Generating Secure Passwords

Published · 9 min read

“Use a strong password” is the kind of advice that everyone repeats and almost nobody defines. This guide is the definition. We will look at what actually makes a password hard to crack — it is almost entirely about entropy, not about sprinkling in symbols — why machines beat humans at picking random strings, the subtle bug that weakens naive password generators, and what current standards bodies recommend. By the end you should be able to look at any password and judge it on sound principles rather than a green strength meter.

Entropy: the only number that matters

Password strength is measured in bits of entropy. One bit of entropy means an attacker who knows your strategy still faces a 50/50 guess. N bits means 2N equally likely possibilities. A fair coin flip is 1 bit. A single decimal digit is about 3.32 bits (log2 10). A lower-case letter chosen uniformly at random is log2(26) ≈ 4.7 bits.

The catch is that word uniformly. Entropy only counts if every symbol is equally likely. A human-picked “random” letter is not uniform — people over-use the middle of the keyboard and avoid letters that feel awkward — so its real entropy is well below 4.7 bits. This is the core reason computer-generated passwords are stronger than human ones at the same length: the machine actually hits the theoretical entropy, while a human does not.

To convert entropy into time-to-crack, multiply by the attacker’s guess rate. A modern GPU rig can try roughly 1010 to 1011 hashes per second on a fast algorithm. At that speed, a 40-bit password (about 8 random lower-case letters) falls in well under a minute. A 60-bit password takes years. An 80-bit password is comfortably out of reach of anything short of a nation-state. The rule of thumb: aim for at least 70–80 bits of real entropy for anything you care about.

Length beats complexity

Old password advice told you to add symbols and mixed case. That raises the alphabet size, which raises per-character entropy, but it comes at a usability cost: the password gets harder to type and harder to remember. The more important lever is length, because entropy scales linearly with length but only logarithmically with alphabet size.

Compare two passwords with roughly the same entropy:

12 chars, full ASCII set (~6.6 bits/char)  ≈ 79 bits  → "k9$Qv2#rLm!7"
16 chars, lower-case only (~4.7 bits/char)  ≈ 75 bits  → "tmvbkzplhqyrnfwx"

Both are strong. The second is easier to type and easier to select with a password manager. Doubling the alphabet size adds only one bit per character; doubling the length roughly doubles the total entropy. This is why modern guidance de-emphasizes mandatory symbols and instead asks for minimum length.

Why humans are bad at this

When you ask someone for a “random” 8-character password, you almost never get 8 uniformly random characters. You get a dictionary word with a digit at the end, or a name with leetspeak substitutions (“a” → “@”). Attackers know this and run dictionaries, not brute force. A wordlist attack tries billions of the most common patterns first — Password1!, qwerty123, names plus birth years — and cracks an enormous fraction of real-world passwords in seconds, even though those passwords technically satisfy “8+ chars, upper, lower, digit, symbol.”

The defense is simple: do not let humans choose. Use a generator that picks each character from a cryptographic random source, or use a passphrase built from words chosen by such a source. The password generator on this site uses the browser’s Crypto.getRandomValues and runs entirely locally — the output never touches a server.

The random source: CSPRNG or nothing

Math.random() in JavaScript is not cryptographically secure. It is a fast pseudo-random generator with a predictable internal state; if an attacker can observe a few outputs, they can reconstruct the state and predict every future — and past — output. For passwords you must use a CSPRNG (cryptographically secure pseudo-random number generator).

Modulo bias: the silent strength-killer

Here is a bug that has shipped in real password generators. You have a CSPRNG and you want a random index into an alphabet of, say, 62 characters. The tempting shortcut is index = randomByte % 62. The problem is that 256 (the number of values a byte can take) is not evenly divisible by 62. The first 8 indices (256 mod 62 = 8 remainder) are each hit by one extra byte value, so they are about 1.6% more likely than the rest. The bias is small but real, and it accumulates: across a 16-character password the first few alphabet characters appear noticeably more often, slightly reducing the real entropy below the theoretical value.

The correct approach rejects values that would introduce bias:

// Rejection sampling — no modulo bias
function unbiasedIndex(alphabetLength) {
  const limit = 256 - (256 % alphabetLength); // largest multiple of N
  const buf = new Uint8Array(1);
  let x;
  do {
    crypto.getRandomValues(buf);
    x = buf[0];
  } while (x >= limit);          // reject the biased tail
  return x % alphabetLength;
}

Or, more simply, use crypto.getRandomValues to fill a buffer of 32-bit integers and reject any value above the largest multiple of the alphabet length. The point is to never reduce a random range with modulo when the range is not a clean divisor.

Passphrases: long, memorable, strong

A passphrase is four to seven random words strung together: correct-horse-battery-staple. From a wordlist of 7,776 words (the EFF Diceware list), each word contributes log2(7776) ≈ 12.9 bits of entropy. Four words give ~52 bits (good for most consumer accounts), five give ~64, six give ~77. Passphrases are easier to type on a phone, easier to remember briefly while you set up a password manager, and they survive being read over the phone — none of which is true of k9$Qv2#rLm!7.

The trade-off is length: a six-word passphrase is 25–35 characters. Some legacy systems cap password length absurdly low, which rules them out. And passphrases are only as strong as the wordlist is random — a phrase you invented (

Use a password manager

A unique, random, 80-bit password per site is not something a human can memorize at scale. The honest answer is a password manager: one strong master password (a passphrase is ideal here) protecting a vault of generated credentials. Every major manager — Bitwarden, 1Password, KeePassXC, Apple Passwords, Chrome’s built-in manager — can generate and fill long random passwords for you.

The benefit is not just strength; it is uniqueness. When one site you use gets breached, the attackers walk away with a hash of your password and try the same password on email, banking, and GitHub. If you reuse passwords, one breach cascades. A manager makes reuse unnecessary, which is arguably a bigger security win than the raw entropy.

What NIST actually says now

NIST Special Publication 800-63B (current revision) overturned much of the old “complexity rules” advice. The key recommendations:

Note what is not on the list: there is no requirement for symbols, no maximum length cutoff, no security questions (those are being phased out as they are guessable), and no forced expiry. If a service you use still enforces 1990s-style rules, that is a signal its password policy has not been updated.

Hashing, briefly

The strength of a password only matters relative to how it is stored. A site that stores passwords in plain text will leak your password no matter how strong it is. Responsible services never store the password; they store a slow, salted hash (bcrypt, scrypt, argon2). A slow hash turns a 1011/s GPU rig into a 104/s crawl, which is why a 60-bit password hashed with argon2 is still safe years later while the same password hashed with unsalted MD5 is dead in minutes. You can experiment with how hashing works (and see why MD5 is obsolete) using the hash generator.

A practical checklist

Strong passwords are not magic. They are the predictable result of using a real random source, picking enough bits, and letting a machine do the choosing. Get those three things right and you are already ahead of the vast majority of accounts on the internet.

Related tools

  • Password Generator — CSPRNG-backed, runs entirely in your browser, configurable length and character sets.
  • Hash Generator — see how SHA-256, SHA-1, and MD5 turn text into fixed-length digests.

← Back to blog