Generate strong random passwords or passphrases
in the browser with crypto.getRandomValues(). The
meter under the list shows entropy in bits, so you can see how
much each extra character adds.
qT7#vLm2$eRxK9pW
stout-repaint-cinch-tummy-gemstone-cactus-runner Add length before you add symbols. Every character multiplies the search space, while swapping an a for an @ barely changes it. For example, 16 random characters from the full 85-character alphabet here is about 102 bits of entropy, far beyond any brute-force attack. The same alphabet at 8 characters is about 51 bits, which a rented GPU cluster can get through in hours.
The old advice about uppercase, a digit and a symbol dates from when passwords were eight characters and people picked them by hand. NIST dropped those composition rules in 2017, because they push people toward Password1! and add almost no entropy. We recommend length, a different password per site, and a password manager to hold them.
The meter labels this Weak. A consumer GPU can guess it over a weekend, so do not use it for anything that matters.
Labeled Reasonable. Fine for a throwaway account behind rate limiting, but not for an account that holds money or data.
Labeled Strong and comfortable for real accounts. A random password of 12 to 15 characters from the full alphabet lands here.
At this point the password is no longer the weak part of your setup, and extra length changes little.
Random bytes come from crypto.getRandomValues(),
which the operating system seeds. Characters are drawn with
rejection sampling instead of a modulo, so every character in
the alphabet is equally likely. A plain
% alphabet.length makes the first few characters
slightly more common, because 256 does not divide evenly by the
alphabet size.
Use at least seven words in Passphrase mode. The words come from the EFF short wordlist: 1,296 words, none longer than five letters, chosen so no two are easy to confuse when typed. That is 10.34 bits per word, so seven words gives about 72 bits. The four words from the xkcd strip give only 41 bits, which is too weak for anything you care about.
The page contains no request that could send a password anywhere, and the values are gone when you close the tab. Even so, we recommend generating the password inside your password manager when you can, so it goes straight into the vault instead of through the clipboard.
const crypto = require("node:crypto");
function password(length = 16, alphabet =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*-_=+") {
const limit = Math.floor(256 / alphabet.length) * alphabet.length;
let out = "";
while (out.length < length) {
const byte = crypto.randomBytes(1)[0];
if (byte < limit) out += alphabet[byte % alphabet.length];
}
return out;
}
console.log(password(20));
// In the browser: crypto.getRandomValues(new Uint8Array(1))
// Never Math.random(). It is fast, predictable, and not seeded for this. The limit check is rejection sampling. A plain byte % alphabet.length makes the first few characters slightly more likely, because 256 does not divide evenly by the alphabet size.
<?php
function password(int $length = 16): string {
$alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*-_=+';
$max = strlen($alphabet) - 1;
$out = '';
for ($i = 0; $i < $length; $i++) {
// random_int is cryptographically secure and unbiased
$out .= $alphabet[random_int(0, $max)];
}
return $out;
}
echo password(20), PHP_EOL;
// Then store it hashed, never in plain text:
echo password_hash(password(20), PASSWORD_BCRYPT, ['cost' => 12]), PHP_EOL; rand() and mt_rand() are not suitable here. random_int() is, and it throws rather than falling back to something weak if the system has no good source.
import secrets
import string
ALPHABET = string.ascii_letters + string.digits + "!@#$%^&*-_=+"
def password(length: int = 16) -> str:
return "".join(secrets.choice(ALPHABET) for _ in range(length))
print(password(20))
# A passphrase from a real word list is easier to type and just as strong
with open("/usr/share/dict/words") as f:
words = [w.strip().lower() for w in f if w.strip().isalpha()]
print("-".join(secrets.choice(words) for _ in range(4)))
# secrets, not random. random is seeded for reproducibility, which is
# the opposite of what you want here. NIST dropped the composition rules (one uppercase, one digit, one symbol) from its guidance in 2017, along with forced periodic rotation. Both push people toward predictable patterns: Password1!, then Password2!. What replaced them is length, a check against known-breached lists, and not reusing anything.
Use a different password on every site. Rate limiting already protects the login form from guessing. The larger risk is a database dump from a site you forgot you had an account on, hashed badly, cracked offline at billions of guesses a second, then replayed everywhere else. Unique passwords defend against that, and in practice that means a password manager.
This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.
From crypto.getRandomValues(), the browser's cryptographically secure generator. The page does not use Math.random(), which is predictable and unsuitable for anything security related.
No. The page contains no server call, so generation happens in your tab and the value exists only there until you copy it.
Use 16 characters from a mixed alphabet for almost any account, and 20 or more for a password manager master password or a root account. Each extra character adds about 6.4 bits with the full alphabet here, far more than swapping in unusual symbols.
Entropy in bits, calculated from the alphabet size and the length. The meter labels under 45 bits Weak, 45 to 69 Reasonable, 70 to 99 Strong, and 100 or more Overkill. It grades the recipe, not whether the exact string has appeared in a breach.
Exclude them when someone will read the password off a screen and type it somewhere else. Exclude look-alikes drops l, I, 1, O and 0, the characters people mistype that way.
Yes. Switch Mode to Passphrase for random words joined by a separator, drawn from the EFF short wordlist of 1,296 words. That is 10.34 bits per word, so the default of seven words is about 72 bits. A passphrase is also much easier to type on a phone or a TV remote than a random string.
To store a password the way a server should, hash it with the bcrypt generator. For random identifiers instead of secrets, use the UUID generator, and for checksums, the SHA generator.