pickuma.
Dev Knowledge

Why You Hash Passwords Instead of Encrypting Them

Passwords are hashed, not encrypted — because you never need to read them back, only check them. Here is why one-way hashing, salts, and slow algorithms like bcrypt matter.

5 min read

If your database stores user passwords in a form you could decrypt back to plain text, you have already lost. The whole point of password storage is that even you cannot recover the original. That is the difference between hashing and encryption, and it is why every serious system hashes.

Encryption Is Reversible — That Is the Problem

Encryption transforms data so it can be turned back into the original, given a key. That reversibility is a feature when you need the data again: TLS encrypts a message so the recipient can decrypt and read it. But it makes encryption the wrong tool for passwords.

If you encrypt passwords, the key that decrypts them has to live somewhere — in config, in a secrets manager, in application memory. An attacker who gets your database and that key can decrypt every password at once. You have turned a credential store into a single-key safe, and the password is the most valuable thing inside.

Hashing is one-way by design. A hash function takes input and produces a fixed-length digest, and there is no “un-hash” operation. The same input always yields the same digest, but you cannot run the function backward to recover the input. There is no key to steal because there is no key.

The key insight is that you never need to read a password back. When a user logs in, you do not need to know their stored password — you only need to know whether the password they just typed is the same one. So you hash the attempt and compare it to the stored hash. Match means correct; no match means wrong. You verify without ever recovering.

Why a Plain Fast Hash Is Not Enough

So you hash with SHA-256 and you are done? Not quite. General-purpose hashes like MD5 and SHA-256 are built to be fast — they are meant to digest gigabytes quickly. For passwords, speed is exactly what you do not want, because it helps the attacker more than you.

Two attacks make a plain fast hash weak:

  • Rainbow tables. Attackers precompute hashes for billions of common passwords and store them in lookup tables. If you store a bare SHA-256 of password123, it is the same digest in every database on earth, so cracking it is a single table lookup.
  • Brute force. Modern GPUs compute billions of fast hashes per second. If the hash is cheap, guessing through huge candidate lists is cheap too.

The fix is two ingredients. First, a salt: a unique random value generated per user and stored alongside the hash. You hash the salt together with the password, so identical passwords produce different digests. That breaks rainbow tables outright — a precomputed table is useless against a salt it never saw, and the attacker must attack each user’s hash separately.

Second, a slow, work-factored algorithm: bcrypt, scrypt, or Argon2. These are deliberately expensive, with a tunable cost parameter. You make one hash take, say, a quarter of a second — unnoticeable on a single login, but devastating for an attacker who needs to try billions of guesses. As hardware gets faster, you raise the cost factor to keep pace.

Putting It Together

A login flow with proper hashing looks like this:

Signup: hash = bcrypt(password, salt, cost) → store hash (salt + cost embedded)
Login: bcrypt(attempt, stored_salt, cost) == stored_hash ?

You never store the password, never decrypt anything, and never hold a key that could reverse the whole table. Even if your database leaks, an attacker faces a per-user, deliberately slow guessing problem rather than a one-key unlock. That is the entire reason the industry settled on hashing: not because it is fancier, but because the only safe password is one you yourself cannot read.

FAQ

FAQ

If I lose a hash, can I get the password back?+
No, and that is intentional. Hashing is one-way, so there is no operation that recovers the original from the digest. This is also why password reset flows email you a link to set a new password instead of sending your old one — the system genuinely does not have it.
Is a salt secret? Where do I store it?+
A salt is not a secret and does not need to be hidden. Its job is to be unique per user so identical passwords hash differently and rainbow tables fail. With bcrypt, scrypt, and Argon2 the salt is stored right inside the output hash string, so you keep it next to the hash in the database.
Why not just SHA-256 with a salt — is bcrypt really needed?+
Salted SHA-256 defeats rainbow tables but is still far too fast, so brute force against a leaked hash stays cheap on modern GPUs. bcrypt, scrypt, and Argon2 add a tunable cost that makes each guess slow, and you can raise that cost as hardware improves. That ongoing expense is what salted SHA-256 lacks.

Related reading

See all Dev Knowledge articles →

Get the best tools, weekly

One email every Friday. No spam, unsubscribe anytime.