Hashing vs Encryption vs Encoding
Three terms that get used interchangeably and mean entirely different things. Getting them confused is behind a striking number of real security incidents.
Three different things
Encoding, encryption and hashing get used interchangeably in conversation and mean completely different things in practice. Confusing them produces real vulnerabilities.
| Encoding | Encryption | Hashing | |
|---|---|---|---|
| Purpose | Compatibility | Confidentiality | Integrity and verification |
| Reversible? | Yes, by anyone | Yes, with the key | No, ever |
| Needs a key? | No | Yes | No |
| Output size | Proportional to input | Proportional to input | Fixed, regardless of input |
| Examples | Base64, URL encoding, hex | AES, RSA, ChaCha20 | SHA-256, bcrypt, Argon2 |
| Provides security? | None | Yes | Yes, for its purpose |
The one-line version: encoding is for machines that expect a particular format, encryption is for keeping secrets from people who lack the key, hashing is for proving something has not changed.
Encoding: not security at all
Encoding transforms data into a different representation so it survives a channel that would otherwise mangle it. There is no key and no secret — the algorithm is public and reversing it is trivial.
Base64: 'password' -> cGFzc3dvcmQ=
URL: 'a b&c' -> a%20b%26c
Hex: 'Hi' -> 4869Base64 exists because some channels are text-only: email bodies, JSON strings, HTTP headers, data URIs. It converts arbitrary bytes into 64 safe characters, at a cost of about 33% extra size.
Percent-encoding exists because URLs reserve characters such as ?, & and # for structure. See the URL encoder.
Base64 is not encryption. This needs saying because it appears in real breach reports: credentials Base64-encoded in a config file, API keys Base64-encoded in a mobile app, tokens Base64-encoded in localStorage. Anyone can decode it in one second with no key. It is obfuscation at best, and it fools only the person who wrote it.
Encryption: reversible with a key
Encryption transforms plaintext into ciphertext using a key. Without the key the ciphertext is indistinguishable from random data; with it, the original is recovered exactly.
Symmetric encryption
One key encrypts and decrypts. Fast enough to encrypt terabytes. The problem is getting the key to the other party safely.
- AES-256-GCM — the standard choice. GCM is an authenticated mode, meaning it detects tampering as well as providing confidentiality.
- ChaCha20-Poly1305 — faster than AES on hardware without AES instructions, common on mobile.
- Avoid ECB mode — it encrypts identical blocks identically, which famously leaves the outline of an image visible after “encryption”.
Asymmetric encryption
A public key encrypts and a mathematically related private key decrypts. This solves key distribution: publish the public key freely.
- RSA-2048 or better — widely deployed, slow, large keys.
- ECDH / Ed25519 — elliptic curve, far smaller keys for equivalent strength. A 256-bit ECC key is roughly as strong as a 3,072-bit RSA key.
In practice both are combined. TLS uses asymmetric cryptography to agree a symmetric session key, then encrypts the actual traffic symmetrically because it is orders of magnitude faster.
Hashing: one-way by design
A cryptographic hash function maps input of any length to a fixed-length digest. The mapping is deterministic and irreversible.
Four properties define a usable hash function:
- Deterministic. The same input always gives the same output.
- Pre-image resistant. Given a digest, finding an input that produces it is computationally infeasible.
- Collision resistant. Finding two different inputs with the same digest is infeasible.
- Avalanche effect. Changing one input bit changes about half the output bits.
SHA-256('hello') = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
SHA-256('hellp') = 6d1b4b8ba1d4e0d6a1e4bb64d95e19f0a4bd0d13b3c39f0bcac1a0e5ff5c30cd
One letter changed. Nothing about the outputs is similar.Which algorithm
| Algorithm | Status | Use for |
|---|---|---|
| MD5 | Broken | Nothing security-related. Collisions can be produced in seconds. |
| SHA-1 | Broken | Nothing new. Google demonstrated a practical collision in 2017. |
| SHA-256 / SHA-512 | Secure | Integrity checks, signatures, blockchains |
| SHA-3 / BLAKE3 | Secure | Modern alternatives; BLAKE3 is very fast |
| bcrypt / scrypt / Argon2 | Secure | Passwords only — deliberately slow |
Generate and compare digests in the hash generator.
Why passwords need a different kind of hash
This is where the distinction matters most, and where the most damaging mistakes happen.
SHA-256 is designed to be fast — that is a feature for verifying file integrity and a catastrophe for passwords. A consumer GPU computes billions of SHA-256 hashes per second, so a stolen database of SHA-256 password hashes is cracked in hours.
Password hashing functions are deliberately slow and memory-hungry:
- Argon2id — winner of the 2015 Password Hashing Competition and the current recommendation. Tunable in time, memory and parallelism.
- scrypt — memory-hard, which specifically frustrates GPU and ASIC attacks.
- bcrypt — older but still sound, with a configurable cost factor. Note its 72-byte input limit.
- PBKDF2 — acceptable where FIPS compliance is required, but the weakest of the four against GPU attacks.
Two further requirements:
Salt. A unique random value per password, stored alongside the hash. Without it, identical passwords produce identical hashes and a single precomputed rainbow table cracks every account at once. All four functions above generate and embed a salt automatically.
Pepper (optional). A secret value stored outside the database — in an environment variable or HSM — and mixed into every hash. If the database alone leaks, the hashes are useless without it.
// Never do this
hash = sha256(password) // fast, no salt
hash = md5(password + 'mysecretsalt') // broken hash, shared salt
// Do this
hash = argon2id(password, randomSalt, memory=64MB, time=3, parallelism=4)More detail in the password security guide.
HMAC and digital signatures
A plain hash proves data has not changed accidentally. It proves nothing about who produced it — anyone can recompute a hash.
HMAC adds a shared secret to the hash, so only parties holding the key can produce or verify the tag. It is how webhook payloads are authenticated: Stripe, GitHub and Slack all sign requests with HMAC-SHA256 so you can confirm the request genuinely came from them.
signature = HMAC-SHA256(key: webhook_secret, message: raw_body)
// Compare with a constant-time function, never ===Use a constant-time comparison. A normal string comparison returns early on the first differing byte, and that timing difference is enough to recover a signature byte by byte.
Digital signatures go further using asymmetric keys: the holder of the private key signs, and anyone with the public key can verify. That gives non-repudiation, which HMAC cannot, because with HMAC both parties hold the same secret. This is what signs software releases, TLS certificates and JWTs using RS256 or ES256.
Choosing the right tool
| You need to… | Use |
|---|---|
| Put binary data in a JSON field or data URI | Base64 |
| Put a value in a query string safely | Percent-encoding |
| Store passwords | Argon2id, scrypt or bcrypt |
| Verify a downloaded file is intact | SHA-256 |
| Keep a file secret at rest | AES-256-GCM |
| Send data securely over a network | TLS 1.3 |
| Prove a webhook came from a partner | HMAC-SHA256 |
| Prove you authored something | Ed25519 signature |
| Deduplicate files | SHA-256 or BLAKE3 |
| Hide a value from casual inspection | Nothing — if it must be hidden, encrypt it properly |
The golden rule: do not implement cryptographic primitives yourself. Use libsodium, the Web Crypto API, your platform’s standard library or a well-reviewed library. Every cryptographic disaster of the last twenty years involved someone writing their own.
Frequently Asked Questions
Is Base64 encryption?
No. Base64 has no key and anyone can decode it instantly. It is a format conversion for transporting binary data through text channels, and it provides zero security.
Can a hash be reversed?
Not mathematically. But a weak password can be found by hashing millions of guesses and comparing, which is exactly why password hashes must use a slow, salted function.
Should I use MD5 or SHA-1?
No. Both are cryptographically broken — practical collisions exist for both. Use SHA-256 or better for integrity, and a dedicated password hash for passwords.
What is a salt and why do I need one?
A unique random value added to each password before hashing. Without it, identical passwords produce identical hashes and one precomputed table cracks every matching account at once.
What is the difference between hashing and encryption?
Encryption is reversible with a key and preserves the data; hashing is one-way and produces a fixed-size digest. Use encryption for secrets you need back, hashing for verification.
Why is SHA-256 wrong for passwords?
It is too fast. A GPU computes billions per second, so stolen hashes are cracked quickly. Argon2id, scrypt and bcrypt are deliberately slow and memory-hard to make that infeasible.
What is HMAC used for?
Proving a message came from someone holding a shared secret. Webhook signatures from Stripe, GitHub and Slack all use HMAC-SHA256 so you can verify authenticity.
Sources & further reading
- NIST SP 800-63B — the current digital identity and password storage guidelines
- OWASP Password Storage Cheat Sheet — concrete parameters for Argon2, bcrypt and scrypt
- SHAttered — the 2017 practical SHA-1 collision from Google and CWI
- RFC 9106: Argon2 — the specification and recommended parameters