Hashing vs Encryption vs HMAC: Three Tools People Keep Confusing
Hashing, encryption and HMAC answer three different questions, and swapping them is how "secure" systems end up with no security at all. This guide explains one-way versus reversible, what a broken hash like MD5 really means, why passwords need slow salted hashing, and which primitive fits which job.
"Encrypt the password." "Hash the token." These phrases get swapped constantly in real code reviews, and the swaps are not pedantic — they are the difference between a system that resists attack and one that only looks secure. The three primitives people mix up answer three genuinely different questions, and once you can state each question in one sentence, picking the right tool becomes mechanical. This article walks through the questions, the failure modes, and the four jobs where the choice actually matters.
One question each
- Hashing answers: "Is this the same content as something I saw before?" A fingerprint — one-way, no key.
- Encryption answers: "Can I hide this content now and read it back later?" A locked box — reversible, but only with the key.
- HMAC answers: "Is this content intact, and did it come from someone who shares my secret?" A tamper-evident seal — one-way like a hash, but keyed like encryption.
The asymmetry that matters most is reversibility. Encryption is designed to be undone with a key. Hashing is designed to never be undone — there is no key, no second half of the operation, nothing to run backwards. HMAC sits in between: it is irreversible like a hash, but producing or checking one requires a shared secret. Almost every real-world confusion is someone reaching for the wrong row of this table.
Hashing: a fingerprint with no undo
A hash function maps any input to a fixed-size digest — 128 bits for MD5, 160 for SHA-1, 256 for SHA-256 — deterministically, so the same bytes always produce the same digest, and with an avalanche effect, so flipping one input bit scrambles roughly half the output. Git, Bitcoin, torrent files, password databases and every deduplication system you have ever used are built on this: compare digests instead of contents.
But "you cannot invert it" does not mean "you cannot learn anything from it." If the set of possible inputs is small, anyone can hash every candidate and compare. The digest of the word "correcthorsebatterystaple" is not a secret; it is a lookup away. A hash only hides information when the input has high entropy. This is the exact trap behind "hashing" API keys or passwords with plain SHA-256 and assuming secrecy.
When a hash is "broken": collisions, not decryption
You will read that MD5 and SHA-1 are "broken," and then see MD5 still used in the wild, which makes the claim sound like marketing. The precise meaning: a hash is broken when collision resistance fails — when an attacker can construct two different inputs with the same digest. MD5 collisions have been trivial since 2004, and by 2008 researchers used chosen-prefix collisions to forge a fraudulent certificate authority. SHA-1 held out until 2017, when Google's SHAttered attack produced a real collision, and in 2020 a chosen-prefix collision was demonstrated for a few tens of thousands of dollars of cloud compute.
Crucially, "broken" does not mean anyone can read your input — preimage resistance survives. It means the digest no longer uniquely represents content, so anything that trusts "same hash, same file" can be attacked: a signed contract that is also valid as a different document, an executable that is also a known-good sample, a certificate that is also a rogue CA. If your threat model includes an adversary who can submit both versions of a file, use SHA-256 or better. If you only need a cache key for content nobody is attacking, MD5 is merely legacy, not on fire.
Encryption: reversible, and only as safe as its key
Encryption transforms plaintext into ciphertext with a key, and — unlike hashing — the operation is designed to be undone. Symmetric schemes like AES use one key for both directions; asymmetric schemes like RSA or elliptic-curve use a key pair so the party that encrypts need not be the party that decrypts. The mathematics of AES is not the weak point in practice; key management is. Hardcoded keys, one key shared across all deployments, or a key file stored next to the ciphertext all collapse the scheme to "obfuscation".
There is a subtler trap: raw encryption does not guarantee integrity. Older modes like CBC produce ciphertext that an attacker can flip bytes in, and history shows the consequences — padding-oracle attacks decrypted traffic by simply watching the server reject malformed padding. The modern default is authenticated encryption, of which AES-GCM is the standard example: it produces a tag that covers the ciphertext, so a single flipped bit fails verification and you never decrypt tampered data at all.
AES-GCM Encrypt / DecryptAuthenticated AES (AEAD) — open the toolPasswords: why hashing must be slow and salted
Storing passwords is the special case where plain hashing is dangerously wrong, for one reason: passwords are low-entropy. A GPU rig tests billions of fast-hash candidates per second, so unsalted SHA-256 over a leaked user table is a solved puzzle for the common passwords. Two countermeasures fix this, and they work together.
First, a salt: a unique random value per user, mixed into the hash. Salts do not make the hash stronger per guess — they make every guess count for exactly one user, and they kill precomputed rainbow tables, because there is no table for "your random 16 bytes plus this password." Second, deliberate slowness: PBKDF2 iterates a keyed hash hundreds of thousands of times (current OWASP guidance: 600,000 iterations of PBKDF2-HMAC-SHA256), while memory-hard alternatives like scrypt and Argon2id force attackers to buy memory as well as compute. The cost model is asymmetric on purpose: a legitimate login spends tens of milliseconds once, while an attacker spends that tens of milliseconds per guess across billions of guesses.
And never encrypt passwords instead of hashing them. Encryption is reversible; a stolen key or a coerced employee dumps every password in plaintext in one step. Hashing at least guarantees the database, even fully leaked, contains nothing directly readable.
PBKDF2 Key DerivationPassword-based key derivation — open the toolHMAC: proving content and origin together
A checksum tells you a file is intact; it does not tell you the file was approved by you. HMAC closes that gap: it is a hash computed with a secret key, so only someone holding the key can produce a digest that verifies. The construction (a key mixed twice into the hash, with inner and outer padding) was designed partly to defeat length-extension attacks that make naive constructions like hash(secret ‖ message) unsafe for older Merkle–Damgård hashes.
You meet HMAC constantly: the HS256 signature on a JWT, the request signing in AWS API calls, the cookie signatures in web frameworks, and the codes inside TOTP two-factor authentication. Note what HMAC does not do: it does not hide anything. The message is still readable; what the tag proves is that the content is untouched and came from a holder of the shared secret. Verify tags with constant-time comparison, because timing differences leak nothing useful but trying to find out is free.
Choosing the right primitive: four jobs
- Verify a download from a stranger: SHA-256 checksum. But remember a man-in-the-middle can swap the file and the checksum together, so fetch the checksum over a different channel, or use a real signature.
- Hide data you must read back: AES-GCM with a key you manage — authenticated, so tampering is caught before decryption.
- Store passwords: PBKDF2 (or Argon2id) with a per-user random salt and a high iteration count. Never encryption, never a fast hash.
- Let a token or request prove it is authentic to a recipient: HMAC if both sides share a secret (JWT HS256, API signing), public-key signatures if many independent parties must verify.
If you can name the question you are actually asking — sameness, secrecy, or origin — you will reach for the right primitive almost every time. The rest is detail: salt per user, authenticate your encryption, and stop trusting digests from 1992. You can compute hashes, HMACs and PBKDF2 derivations side by side right here, entirely in your browser.
Hash GeneratorMD5, SHA, RIPEMD, HMAC — open the tool