DEV Community

pickuma
pickuma

Posted on • Originally published at pickuma.com

Why You Hash Passwords Instead of Encrypting Them

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.

For passwords, reach for bcrypt, scrypt, or Argon2 with a unique per-user salt — never a fast hash like MD5 or SHA-256, and never reversible encryption. Modern algorithms like Argon2 also resist GPU and memory-hardware attacks in ways a salted SHA-256 cannot. Most libraries store the salt and cost factor inside the output string, so you do not manage them by hand.

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 ?
Enter fullscreen mode Exit fullscreen mode

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


Originally published at pickuma.com. Subscribe to the RSS or follow @pickuma.bsky.social for new reviews.

Top comments (0)