Hashing, MACs, and Storing Passwords

"Just hash the password" is advice that's simultaneously right and dangerous — right that you never store plaintext, dangerous because a fast cryptographic hash like SHA-256 is exactly the wrong tool for passwords. Hashing, message authentication, and password storage are three different jobs that all involve hashing, and confusing them is a classic source of real breaches.

The integrity guarantee comes from hashing. This post covers cryptographic hash functions, how they combine with a key to give authenticity (MACs/HMAC), and the special, frequently-botched case of password storage — where ordinary hashing is actively wrong and you need deliberately-slow password hashing. These are distinct tools that share the word “hash,” and telling them apart is essential applied crypto.

Cryptographic hash functions

A cryptographic hash function takes any input and produces a fixed-size output (a digest or fingerprint) — SHA-256 produces 256 bits regardless of input size. Its security properties are what make it cryptographic (not just any hash like a CRC):

Use SHA-256 (or SHA-3, or BLAKE2/BLAKE3) — standard, vetted hashes. Do not use MD5 or SHA-1 for security; both are broken (practical collisions found) and survive only in legacy non-security contexts. Hashes give integrity: publish a file’s SHA-256, and anyone can verify the file wasn’t altered by recomputing it. They’re also the building block for MACs, signatures, and more. But note a bare hash’s limit: it detects accidental change and lets you verify against a trusted digest — but if an attacker can change both the data and the published hash, a bare hash proves nothing. Closing that gap needs a key.

From integrity to authenticity: MACs and HMAC

A bare hash gives integrity only if the digest itself is trustworthy. To get authenticity — proof the data came from someone who holds a secret — you combine a hash with a secret key, producing a MAC (Message Authentication Code):

MACs are why AEAD ciphers include an authentication tag (it’s a MAC over the ciphertext), why API requests are often signed with HMAC, and how integrity+authenticity are enforced in countless protocols. When you need “this data is unchanged and from a trusted source,” a MAC (HMAC) is the tool — not a bare hash.

Passwords: where ordinary hashing is wrong

Now the frequently-botched case. You must never store passwords in plaintext — that’s obvious. The trap is thinking “so I’ll SHA-256 them.” A fast cryptographic hash is the wrong tool for passwords, and here’s why:

The correct approach: a slow, salted password-hashing function designed specifically for this:

So password storage is not the integrity use of hashing — it’s a distinct problem needing a distinct tool. “Hash the password” is right in spirit (never store plaintext, the operation is one-way) but wrong in specifics if you reach for SHA-256. The right answer is Argon2/scrypt/bcrypt with per-password salts and a tuned work factor.

Three jobs, three tools

The through-line: hashing appears in three different jobs, and using the right variant matters:

Confusing these is a classic failure: using SHA-256 for passwords (too fast, crackable), using a bare hash where you needed a MAC (no authenticity — attacker changes data and hash), or using a slow password hash for bulk integrity (needlessly slow). Match the job to the tool: fast hash for integrity, HMAC for authenticated integrity, deliberately-slow salted hash for passwords. Next: public-key cryptography, which solves the key-distribution problem that symmetric encryption and MACs both assume away.

Key takeaways

Further reading

Sources & References

Argon2/scrypt/bcrypt and salting