A well-built site doesn’t know your password. Not because it would rather not: because it can’t.
That sounds like a dodge, because every time you type it the system lets you in, and to let you in it has to check something. But checking isn’t knowing. The server keeps a fingerprint computed from your password; when you type, it computes the fingerprint again and compares. If they match, in you go. At no point does the password itself need to be written down anywhere.
Which gives you the clearest tell there is for separating a serious service from one that isn’t: if you forget it and they email it back to you, they had it stored. And anything stored ends up, sooner or later, in somebody else’s hands.
1979 the idea of not keeping them — and the idea of doing it slowly
In 1979, Robert Morris and Ken Thompson published “Password Security: A Case History” in Communications of the ACM, describing what they had done in Unix. It reads as a field report, and it sets down two ideas we now take as obvious.
The first one wasn’t theirs — storing the hash instead of the password was already being done — but nobody had explained it better: don’t store the password, store its hash. A function that turns your password into an arbitrary-looking value and can’t be walked backwards: from the hash you don’t get back to the password.
The second one is theirs: the salt. A random value, different for every user, mixed into the password before the hash is computed. Without salt, two people with the same password have the same hash — the stolen file turns into a game of spot-the-duplicate — and, worse, someone can precompute one giant table once and use it against every database on earth. Salt doesn’t make your password harder to guess: it makes guessing it useless to anyone else.
But there’s a third idea in that same paper, cited far less often, and it’s the one that matters here: they made the function deliberately slow. Not by oversight. On purpose. Encrypting a password cost far more than it technically needed to, because someone who logs in once each morning doesn’t care, and someone trying millions of candidates does.
The whole business, in a sentence written almost fifty years ago.
Why slowness is the only honest defence
Nearly every defence in computing is asymmetric: cheap for the defender, expensive for the attacker. Encrypting is cheap; decrypting without the key is hopeless. The defender plays with a structural advantage.
Password storage doesn’t work like that. Here the defender and the attacker run exactly the same function. You compute the hash to check that you got it right; he computes it to check whether he got it right. It’s the one race in security where both of you run on the same legs.
When you can’t outrun your rival, there’s only one move left: make the track expensive for both of you. You pay that cost once per login. He pays it once per attempt. Since he needs orders of magnitude more attempts than you do, the same bill lands on the two of you in wildly different ways. That’s what a password hash is for.
Which is why functions that are fast and excellent at other jobs — SHA-256, say — are a terrible pick here. They’re fast. Fast is precisely what we don’t want.
1999 bcrypt, and cost as a dial
The trouble with a slow function is that hardware doesn’t sit still. What was slow in 1979 is instant later on. A defence calibrated against one decade’s computers ages all by itself, with nobody touching it.
In 1999, Niels Provos and David Mazières presented bcrypt at the USENIX Annual Technical Conference, under a title that says it all: A Future-Adaptable Password Scheme.
The idea: put the cost not in the function, but in a parameter. bcrypt carries a cost factor you choose, stored alongside the hash. If hardware gets much faster, you turn the number up and new passwords cost what they ought to again, without changing algorithm.
It’s a design that assumes its own obsolescence and prepares for it. Very little software does that.
2009 scrypt, and the discovery that time isn’t enough
bcrypt makes compute time expensive, and it worked. Until the attacker stopped using the same kind of machine as the defender.
A server has a handful of fast, general-purpose cores. A GPU has an obscene number of tiny cores doing the same thing in parallel, and an ASIC goes further: silicon built to run one single operation. If your defence amounts to “this operation costs X”, someone can build hardware that does many X at once. The defender still has his server.
In 2009, Colin Percival presented scrypt with a different argument: Stronger Key Derivation via Sequential Memory-Hard Functions. If the cost lives only in the computation, it parallelises. But memory isn’t free. Force the function to use a lot of RAM and to walk through it in a way that can’t be dodged, and suddenly the attacker can’t just multiply cores: each core would need its own memory. And GPU cores have plenty of power and very little RAM apiece.
Percival didn’t make the operation expensive. He made the hardware needed to repeat it at scale expensive. That’s a change of level: it goes after the attacker’s budget, not his clock.
2015 Argon2, and the end of the argument
Having several reasonable options helped nobody choose. So the cryptographic community did what it usually does when it wants a matter settled: held a public contest. The Password Hashing Competition took candidates, put them through open analysis for years and in 2015 declared Argon2 the winner.
Argon2 inherits both lessons: cost in time and cost in memory, each tunable separately, plus the number of threads. It isn’t magic. It’s the tidy synthesis of 1979, 1999 and 2009, reviewed by people whose job was trying to break it.
What this means for you
Almost none of this is in your hands, and that’s worth saying out loud: the site picks the hash, not you. You can have the best password in the world and have them keep it in plain text in a spreadsheet.
But the other side of the equation is yours. This whole edifice — the salt, the cost, the memory — exists to make each attempt expensive for the attacker. What decides how many attempts he needs is your password. If it’s in a dictionary, no slow function saves you: it’ll fall among the first. If it’s long and looks like nothing at all, that price per attempt gets multiplied by a number of attempts that doesn’t fit in the time available.
That’s why our generator measures bits of entropy rather than percentages, and why the checker looks for your password in dictionaries before it counts symbols. They set the price per attempt; you set the number of attempts. Neither half works without the other.
And yes: it’s still the same old question. Only now, on the other side, someone is trying to answer it many times a second, and we’ve spent since 1979 trying to make every one of those times cost him money.
Sources: R. Morris and K. Thompson, “Password Security: A Case History”, Communications of the ACM, 1979 · N. Provos and D. Mazières, “A Future-Adaptable Password Scheme”, USENIX Annual Technical Conference, 1999 (bcrypt) · C. Percival, “Stronger Key Derivation via Sequential Memory-Hard Functions”, 2009 (scrypt) · Password Hashing Competition, winner Argon2, 2015.