Hashing
Method
A method of storing a value as a string it can't be turned back into, used where the original never needs to be read again.
Why it exists
Services once kept passwords in the database exactly as the user typed them. Support could look yours up and read it back to you over the phone, and password-reminder emails sometimes arrived with the original password printed inside. It was convenient, so it lasted a long time.
The cost showed up the first time one of those tables leaked. What walked out wasn't ten accounts but millions of usernames paired with their passwords. Worse, people reuse the same password across services, so running a leaked list against other sites opened a meaningful share of them. One company lost the data and the damage spread to every service those people had ever signed up for.
That flipped the question. Not how to guard the list better, but whether the list could be stored in a form that's useless to whoever takes it. The answer came from noticing that a service has no actual reason to know the original password. It only needs to know whether what was typed matches what was set earlier, and that judgment doesn't require the original.
How to run it
Put the value through a function that only runs one way, store the string that comes out, and later run the same function again and compare the outputs. The same input always produces the same string, but there's no path back from the string to the input.
The procedure has four steps.
- When storing, generate a random value per account, attach it to the password, run the pair through the function, and save both the resulting string and that random value. The original is kept nowhere.
- When checking, attach the saved random value to whatever password was typed, run the same function, and see whether the result matches the stored string. A match is a pass. The original is never used in that comparison.
- Choose a function that is slow on purpose — bcrypt or Argon2, both built to spend real time on a single computation. Fast functions like MD5 or SHA-1 allow billions of guesses per second, which shreds short passwords.
- Raise the strength periodically. These functions take a work-factor setting, so it gets increased as hardware gets faster, and the stored value is recomputed under the new setting the moment a user logs in successfully.
The random value in step 1 is called a salt. Without it, everyone who chose the same password ends up with an identical stored string. One precomputed table of common passwords sweeps the whole list at once, and seeing the same string repeated ten thousand times is itself enough to reveal that it's a common password. A per-account salt makes identical passwords store differently, which forces an attacker to work one account at a time. The salt isn't a secret and doesn't need to be hidden; storing it next to the hash is normal. Its only job is to make every stored value unique so that work done against one account buys nothing against the next.
When it fits and when it doesn't
It fits wherever the original will never be read back. Passwords are the obvious case, and so are session tokens and the recovery codes behind multi-factor authentication (MFA), since all of those only ever get compared. Authentication, the procedure for confirming who someone is, is comparison all the way down.
Two other uses come up. One is detecting change: keep the hash of a file, hash the copy you downloaded, and any single altered character shows up in the comparison. The other is matching without handing over the raw data, such as two companies trading lists of hashed email addresses to find overlapping customers rather than trading the addresses themselves. Neither side learns an address it didn't already have, and the strings that match point at the accounts both lists contain.
There are three limits.
- It can't be used for anything that has to be read later. Document contents and shipping addresses have to be displayed again, so those belong to encryption.
- It does almost nothing when the set of possible values is small. Phone numbers are a finite space, so trying all of them finds the match. This is why documents claiming that personally identifiable information (PII) is de-identified because it was hashed tend to fall apart under review.
- It protects storage only. The wire is Transport Layer Security (TLS)'s job. A typed password travels as itself until it reaches the server, so an open connection makes careful storage irrelevant.
How it sounds at work
"Passwords are hashed, so we can't see them either."
The original isn't on the server, which means staff can't look it up.
"This is hashed with MD5. By current standards that's barely better than nothing."
The function is fast enough that guessing breaks it.
"Don't write that hashed emails are de-identified. You can just try them."
The value space is small enough that hashing doesn't hide the original.
When Pagedeck went through its first enterprise security review, Theo reopened the login code he'd written early on. Passwords were stored behind a single pass of SHA-256 with no salt. Nothing had leaked, so it wasn't an incident, but any account using a common password would have opened the moment the table walked out.
Migrating is awkward precisely because the originals are gone — there's no way to unwind the stored values and feed them through a new function. Theo's approach was to wait for each user's next login, the one moment the original is briefly in hand: check it against the old scheme, let the login through, then immediately recompute under the new scheme and overwrite. Three months later, the accounts that hadn't come back were made to set a new password.
What people get wrong
The most common mistake is filing hashing under encryption. Both produce unreadable strings, so grouping them feels natural. But encryption has a key, and whoever holds the key reads the original back. Hashing has no such key. Miss that distinction and you get a design that encrypts passwords instead of hashing them, which means a compromised server hands back every password in plain text.
The other one is reading "it's hashed" as "it's safe." Irreversibility sounds like a defense on its own. In practice nobody tries to reverse it; they guess. Feeding a list of common passwords through the function and matching the output against stored values is the whole attack, and with a fast function and no salt a large share of accounts fall within hours. Irreversible means it can't be undone, not that it can't be guessed. The slow function and the salt are what make guessing expensive, and a stored hash without them is a lock with the tumblers already lined up.
Easily confused with
| Term | Can it be reversed | How it differs |
|---|---|---|
| Encryption | Yes, the content comes back for whoever holds the key | Used for values that have to be read later, so where the key lives and who holds it becomes the center of the design. Hashing has no key, so that question never arises |
Where to go next
- Application security
see which defensive layer this method sits in
- Encryption
its counterpart in the same layer, with the opposite property
Last updated 2026-09-16