When you sign up for a website, you pick a password. When you log in next week, the site checks that you typed the same one. The obvious way to do that is to save your password and compare. A well-built site never does that. It saves a kind of fingerprint of your password instead, one that can be checked but can't be turned back into the password. This page shows how that fingerprint, called a hash, works, and the two tricks (salt and slowness) that make it safe.

Why not just save the password?

Websites keep their user accounts in a database: basically a big table with a row per user. Databases get stolen. It happens to small sites and huge companies alike, through bugs, misconfigured servers, or a lost backup. When it happens, whoever has the copy can read every row.

If the password column holds the real passwords, the thief now knows them all. Worse, most people reuse passwords, so the thief can try each email-and-password pair on email providers, banks and shops. The goal of password hashing is simple: even if the database leaks, the passwords should not.

A hash is a one-way fingerprint

A hash function is a recipe that takes any input (one letter, a password, a whole book) and churns it into a fixed-size jumble of numbers called a hash (or digest). A famous one is SHA-256 (Secure Hash Algorithm, 256-bit). Its output is always 256 bits (ones and zeros), which is usually written as 64 hexadecimal characters: the digits 0–9 plus the letters a–f.

Type anything below. The hash is computed live, in your browser.

Live SHA-256

Play with it for a minute and you'll notice the three properties that make hashes useful:

You can do the same thing in Python with the built-in hashlib module. Note the b before the quotes: hashes work on raw bytes, not text.

import hashlib
print(hashlib.sha256(b"abc").hexdigest())
# ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad

A tiny change, a totally different hash

A good hash has one more property, called the avalanche effect: change a single character of the input and about half of the output bits flip. The new hash looks completely unrelated to the old one. That means a hash gives an attacker no hints like "you're getting warmer". Compare two inputs here; differing characters are highlighted.

Spot the difference

Usually around 128 of the 256 bits differ, roughly what you'd get from two random hashes. Even hello versus Hello (one capital letter) produces unrelated results.

How a login check works

So here's the plan. When you sign up, the site hashes your password and saves only the hash. When you log in, it hashes whatever you just typed and compares the two hashes. If they match, you typed the same password. The site never needs to keep the password itself.

SIGN UP "tulip42" hash 9f3a…c1 save database LOG IN typed text hash ????…?? equal? yes → let in
The database only ever sees hashes. The password lives in your head (and your password manager).

That's the core idea, but plain hashing alone has two weaknesses. Let's look at what a thief sees.

The leaked database, three ways

Below is a tiny stolen user table. Switch between how the site stored passwords, then let the attacker run a lookup table: a pre-computed list of the hashes of common passwords like 123456 and sunshine. Attackers build these once and reuse them on every leak. Rows with the same coloured dot have identical stored values.

Stolen users table

userwhat's storedattacker gets

With plain hashes, two problems show up right away:

Salt: a random extra bit per user

The fix is a salt: a random string the site generates for each user when they set their password. The site hashes salt + password and stores both the salt and the hash. The salt isn't secret; it sits right there in the database next to the hash. Its job is to make every user's hash unique.

Look at the salted view above again. Ada and Chloe still have the same password, but different salts, so their hashes look nothing alike (avalanche effect!). And the attacker's pre-computed table is useless, because it was built without these salts. To crack Ada, they now have to hash salt_of_ada + guess for every guess, and then start all over again for Chloe.

Here's what the login check looks like with a salt. The site stored this record when the user ada signed up with the password tulip42. Try logging in.

Login check simulator

    Notice the site never "decrypts" anything. It can't: there's nothing to decrypt. It just repeats the same recipe on what you typed. That's also why a good site can never email you your old password. It can only let you set a new one. If a site can send you your password, it's storing it in a way that can be reversed, which is a red flag.

    Why fast hashes are the wrong tool

    Salt stops shortcuts, but the attacker can still just guess, one user at a time. And SHA-256 was designed to be fast, because it's used for things like checking that a big download isn't corrupted. Fast is great there, terrible here: a single high-end gaming graphics card can try roughly 20 billion SHA-256 guesses per second.

    So password storage uses hash functions that are deliberately slow. The best known are:

    Both build the salt in for you. You'd never write sha256(salt + password) yourself in a real app; you call a library like bcrypt or argon2 and it handles salt, cost and comparison. The calculator shows why the slowness matters.

    How long to try every password?

    The guess rates are rough figures for one top-end graphics card (an RTX 4090, from public hashcat benchmarks). Real attackers may rent many cards, so divide by a few hundred. Two caveats keep this honest: these are times to try every possibility, and real attackers try likely passwords first. If your password is sunshine, it's in every guess list and falls in the first second, whatever the hash. Slow hashing buys time for decent passwords; it can't save terrible ones.

    Check yourself

    A site's database leaks. It stored SHA-256 hashes with no salt. Two users have the exact same hash. What does the attacker know?

    Same input always gives the same hash, so identical hashes mean identical passwords. (And because of the avalanche effect, similar passwords would not look similar.) A per-user salt hides this.

    Does the salt need to be kept secret?

    The site needs the salt at every login to redo the hash, so it's stored in plain sight. Its job is to be unique per user, not secret: it kills pre-computed tables and makes the attacker crack each user separately.

    Why use bcrypt or Argon2 instead of SHA-256 for passwords?

    SHA-256 isn't reversible either. The problem is that it's fast, so guessing is cheap. A slow hash makes every single guess expensive for the attacker while costing a normal login almost nothing.

    You click "forgot password" and the site emails you your current password. What does that tell you?

    A hash can't be turned back into the password, so a site that hashes properly can only offer a reset link. Getting your old password back means it's stored in plain text or reversible encryption. Change that password anywhere else you've used it.

    The short version