A password your browser makes on its own.
Every character comes out of your browser's cryptographic random source, the same one it uses for TLS keys. Random characters for the passwords a manager will remember for you, or diceware words for the ones you have to type yourself. There is no server on the other end of this page, so there is nothing to send the result to and nothing to keep it in.
Generated in this tab, from your browser's own randomness
Password
20 characters · 130 bits
Very strong
130 bits
Guessing stops being the way in at all.
The setting that decides the answer. Every extra character multiplies the number of passwords an attacker has to work through.
Need the hash rather than the password? Hash this one with bcrypt — it is handed over in memory, never through the URL, and the hashing runs in this tab too.
Where the randomness comes from
A password generator is only as good as its source of surprise, and there are two ways to get this wrong in about the same number of lines of code.
The first is Math.random. It is a seeded generator built for shuffling animations, its output is reproducible, and its internal state can be reconstructed from a short run of the numbers it just gave you. On a page that hands out passwords, that means anyone who has one of them is a step away from the rest. This page uses crypto.getRandomValues instead, which is the browser's CSPRNG — the one behind TLS keys and session identifiers.
The second is quieter. Turning a random 32 bit number into a character with % looks harmless, but 2³² is not a multiple of 90, so the first few characters of a 90 character alphabet come up slightly more often than the rest. The fix is to throw away the values in that short tail rather than fold them back in, which costs an occasional extra draw and nothing else:
const range = 4294967296; // 2^32
const limit = range - (range % max); // the largest exact multiple of max
const buffer = new Uint32Array(1);
for (;;) {
crypto.getRandomValues(buffer);
if (buffer[0] < limit) return buffer[0] % max;
}The "at least one from each set" option has the same shape of problem. The usual implementation plants one character from every required set and shuffles, which leaves a smaller and lumpier set of reachable passwords than the length suggests. This one draws the whole password uniformly and discards it if a set is missing, so every valid password stays exactly as likely as every other — and the bit count on the panel is the exact size of that set, worked out by inclusion–exclusion rather than rounded off.
Length is the setting that matters
With your current sets, each character is worth about 6.5 bits. The bars are drawn to scale, so the difference between 8 characters and 32 is the difference in the picture. Pick one to try it.
Words, for the ones you have to type
Some passwords never get typed by a person: they go from here into a password manager and come back out by autofill. Others you have to read off a screen, say down a phone, punch into a TV remote or remember — a disk encryption password, the master password on the manager itself, the WiFi key you give to visitors. That is the job words are for.
The method is diceware, and it is old enough to predate the web. Five dice give 7,776 outcomes, each outcome is one word on a list, and the roll is the whole of the security. This page rolls with the same crypto.getRandomValues as the character mode, on the Electronic Frontier Foundation's long wordlist — words chosen to be easy to type and hard to mishear, with no word a prefix of another. It sits in this site's repository unchanged, under CC BY 3.0 US, so you can diff it against the EFF's own copy and see that nothing was added or taken out.
The part people get wrong: every word is worth exactly 12.925 bits, whether it came out as zoo or abdominal. The attacker is not guessing letters, so a longer word is not a stronger one — it is only more to type. Assume they have the list and know the separator, because they do; the figures on this page already assume it. What you are buying is the count, and nothing else.
- Repeats are allowed
- Two of the same word in one phrase is not a bug. Refusing repeats would shrink the set of possible phrases, and the arithmetic on this page would stop being true.
- The separator is free
- Hyphen, full stop or space, it is the same for every phrase here, so it costs an attacker one guess rather than any real work. Pick whatever the box you are pasting into will take.
- Capitals are free too
- Capitalising every word is a fixed rule, so it adds nothing. It is here because forms ask for an uppercase, not because it helps.
- The digit is not free
- It is drawn one in ten, the same way as everything else, so it is worth 3.3 bits — and the entropy figure counts it.
Where words lose: length. Six words with hyphens is around 45 characters, which walks straight into forms with a 16 character maximum and into bcrypt's 72 byte limit at about ten words. If the box is small, the character mode gets more out of every character.
Two things decide whether guessing works
Cracking a leaked password is hashing candidates until one matches. How fast that runs is the site's choice of hash; how long the list of candidates is, is yours. Same attacker in every row below — one rig, eight current graphics cards — against the password on the panel above and against one a person would have come up with instead.
| Stored with | This password · 130 bits | Invented · 30 bits |
|---|---|---|
| MD5 Salted or not, it is this fast | 10¹⁹ years | instantly |
| SHA-256 One round, the usual mistake | 10¹⁹ years | instantly |
| bcrypt at cost 12 4,096 iterations per guess | 10²⁷ years | 12 hours |
The generated password holds every row, whatever the site did with it. The invented one lasts exactly as long as the hash makes it last: hours behind bcrypt, no time at all behind SHA-256. That is the whole case for generating rather than thinking of one — it takes the decision out of the hands of whoever built the login form.
And if you are the one building it, the gap in that last column is yours to pick: bcrypt or Argon2id, not SHA-256. Thirty bits is a generous estimate for a password somebody invented, the rates are order of magnitude figures rather than measurements, and both assume the average case: half the keyspace before a hit.
What this page does not do
Every item below is something you can check yourself rather than take on trust. Open the network tab and generate a hundred passwords, or turn the connection off and keep going.
- No request, ever
- Generating makes no network call. The page is static files that were already downloaded when it loaded, and the generator is a couple of hundred lines of JavaScript in that bundle.
- Nothing kept
- No cookie and no local storage at all. The only thing in session storage is the scroll position the router puts there for the back button, and nothing about the password is written anywhere. Reload the page and it is gone from everywhere except your clipboard.
- Nothing in the URL
- Settings and output stay out of the address bar, so nothing lands in your history or in a referrer header on the way to the next page. That is also why the link to the bcrypt tool passes the password in memory instead.
- Nobody else on the page
- No analytics, no tag manager, no fonts or scripts loaded from another domain. There is no third party here to measure what you generated, and no backend of ours that could receive it either.
- Prerendered, not made on a server
- The HTML was built once, ahead of time, with no password in it — view the source and the field is empty. The first password is made after the page loads, in your tab.
The one part outside the page's control is the clipboard. Anything running on your machine can read it until you copy something else, so paste the password where it is going and move on.