Hashing Explained: MD5, SHA-256, and Why Hashing Is Not Encryption
2026-08-10
Paste any text into a hash tool and you get back a string like 5d41402abc4b2a76b9719d911017c592. Change a single character of the input and the output is completely different. That one-way transformation is the foundation of password storage, file integrity checks, digital signatures, and much of blockchain — yet it’s also one of the most misunderstood pieces of applied cryptography. Developers routinely “encrypt” passwords with MD5, or treat a hash as proof that data is secret. This guide explains what a hash function actually guarantees, where each algorithm fits, and the mistakes that still get systems breached.
What a Hash Function Actually Does
A cryptographic hash function takes input of any length and produces a fixed-length output — the hash or digest. Four properties make it useful:
- Deterministic: the same input always produces the same hash.
- Avalanche effect: flip one bit of input and roughly half the output bits change. There is no visible relationship between “hello” and “Hello” hashes.
- One-way: given a hash, there’s no practical way to recover the input. This is the crucial difference from encryption.
- Collision-resistant: it should be infeasible to find two different inputs that produce the same hash.
That last property is where algorithms live or die. When security researchers say a hash function is “broken,” they mean collisions can be found deliberately — not that you can reverse it.
You can see all four properties in action with the Hash Generator: hash hello, then Hello, then a 10,000-word document. The outputs are the same length and share nothing in common.
MD5 and SHA-1: Broken, but Not Useless
MD5 (128-bit output, 32 hex characters) was published in 1992 and thoroughly broken by 2008, when researchers used it to forge a rogue SSL certificate. SHA-1 (160-bit) held out longer, but Google demonstrated a practical collision in 2017 with the SHAttered attack — two different PDF files with the same SHA-1 hash.
“Broken” has a precise meaning here: an attacker with enough compute can construct two inputs with the same hash. That’s catastrophic for certificates and signatures, where someone can make a malicious file inherit the trusted hash of a benign one.
Yet MD5 and SHA-1 refuse to die, and sometimes that’s fine. If you’re using a hash as a checksum — did this file get corrupted in transit? is this cache entry stale? — collision attacks are irrelevant, because nobody is trying to deceive you; you just want a fast fingerprint. MD5 remains common in ETags, cache keys, and data deduplication for exactly this reason.
The rule is simple: MD5 and SHA-1 are acceptable for integrity checks you control, and unacceptable for anything involving an adversary — signatures, certificates, password storage, or file integrity of downloads from untrusted sources.
SHA-256 and Friends: The Current Standard
SHA-256, part of the SHA-2 family, produces a 256-bit (64 hex character) digest and remains unbroken after two decades of scrutiny. It’s the default choice when you need a security-grade hash: verifying downloaded files, content addressing (Git uses SHA-1 historically and is migrating to SHA-256), API request signing, and blockchain proof-of-work.
Two adjacent tools worth knowing:
- HMAC is not a hash algorithm but a construction:
HMAC(key, message)mixes a secret key into the hashing process. Use it when you need to prove a message came from someone holding the key — webhook signature verification is the classic case. A plain SHA-256 of the message can’t do this, because anyone can recompute it. - SHA-3 (Keccak) is a completely different internal design standardized in 2015 as insurance against a future break in SHA-2. It’s sound, but SHA-2 is still fine — don’t migrate for the sake of it.
Hashing Is Not Encryption (and Passwords Are the Proof)
Encryption is reversible: ciphertext plus key gives back the plaintext. Hashing is irreversible by design. You will still find legacy codebases that “encrypt passwords with MD5” — a sentence that describes two bugs at once. MD5 is a hash, not encryption, and a fast general-purpose hash is the wrong hash for passwords anyway.
Here’s why. Attackers don’t reverse hashes — they guess. A GPU rig computes billions of MD5 or SHA-256 hashes per second, so a leaked database of unsalted SHA-256 password hashes falls quickly: hash every word in a dictionary, every password123 variant, and match them against the database. Rainbow tables — precomputed hash-to-password maps — make it nearly instant.
Proper password storage fights this with three defenses:
- Salt: a random value stored alongside each hash, hashed together with the password. Identical passwords now produce different hashes, and rainbow tables become useless.
- Slow hashing: algorithms like bcrypt, scrypt, or Argon2 are deliberately expensive — tuned to take, say, 100ms per attempt. Billions of guesses per second collapse to a handful. Argon2 also demands large amounts of memory, which neutralizes GPU and ASIC advantages.
- Work factor: these algorithms take a cost parameter you raise as hardware improves.
So the correct recipe is: Argon2id(password, random_salt) — or bcrypt/scrypt if your platform dictates — and never SHA-256 alone, no matter how strong it is as a general hash. If you want a feel for what makes a password hard to guess in the first place, try candidates in the Password Strength Checker; for generating credentials that are random to begin with, the Password Generator produces them locally in your browser.
Everyday Uses That Have Nothing to Do with Security
Once you stop thinking of hashing as a security-only tool, it shows up everywhere:
- File integrity: the
SHA256SUMSfile next to a Linux ISO. You hash your download and compare — transmission errors and tampering both show up as mismatches. - Deduplication: storage systems hash each block and keep one copy per unique hash.
- Hash maps: the
O(1)lookup in every language’s dictionary type is a (non-cryptographic) hash bucketed into an array. - Cache busting:
app.a3f2c9.jsin a build pipeline is a content hash — the filename changes exactly when the content does, so caches can be aggressive safely. - Commit identity: a Git commit ID is a hash of the commit’s content; any tampering with history changes every downstream hash.
In all of these, speed matters and collision attacks don’t, so fast non-cryptographic hashes (xxHash, MurmurHash) often beat SHA-256.
Quick Reference
- Need a security-grade digest: SHA-256.
- Need to authenticate a message with a shared secret: HMAC-SHA-256.
- Storing passwords: Argon2id (or bcrypt/scrypt) with a unique random salt — never a fast general-purpose hash.
- Integrity checks under your own control: MD5/SHA-1 are tolerable, but SHA-256 costs little and ends the debate.
- Never say “encrypt with MD5.” Hashing is one-way; if you need to get the data back, you need encryption.