Hashing vs encryption vs encoding
Published
Three words that get used as if they were the same. They are not even close, and the quickest way to tell them apart is one question: who can get the original back?
- Encoding: anyone. It just changes the format so data survives a trip, like writing a phone number in words so it fits a form. Base64, URL encoding, UTF-8.
- Hashing: nobody. It turns any input into a fixed size fingerprint, and there is no way back. SHA-256, bcrypt, Argon2.
- Encryption: only whoever holds the key. AES, ChaCha20, RSA.
A startup stores user passwords encrypted with AES, with the key in an environment variable, so they can 'recover' a password for users who forget it. Is that safe? What would you change?
Try it#
Type anything below. The page computes all three for real in your browser.
Watch three things as you type. The Base64 row grows with your input and decodes back without any key, so it hides nothing. The SHA-256 row is always 64 hex characters, and a one character change scrambles about half its bits, which is called the avalanche effect. The AES row is different every time you encrypt the same text, because each encryption uses a fresh random IV, yet the key holder gets the exact original back.
Encoding: for compatibility, never for secrecy#
Base64 exists because some channels only carry text: email bodies, JSON fields, URLs, HTTP
headers. It maps every 3 bytes to 4 printable characters, so a file grows by a third. It is
completely public. If you see a "secret" that ends in ==, it is probably Base64, and it is
not secret. Kubernetes Secrets are Base64 encoded by default, which surprises people every
year: anyone who can read the object can read the secret. Encryption at rest has to be turned
on separately.
Hashing: fingerprints#
A cryptographic hash is a one way function with three promises: the same input always gives the same output; you cannot find an input from its output; and you cannot find two inputs with the same output. Uses:
- Integrity. Download a Linux ISO, compare its SHA-256 with the published one.
- Deduplication and addressing. Git names every object by its hash. Dropbox style sync identifies chunks by hash.
- Passwords. Store a hash, not the password. At login, hash what the user typed and compare.
Why SHA-256 is wrong for passwords#
SHA-256 is built to be fast. That is great for checking a 4 GB file. It is terrible for passwords, because an attacker who steals your hash table can try guesses as fast as the hash runs. Password hashes are built to be slow and memory hungry on purpose, with a salt (a random value per user, stored next to the hash) so identical passwords get different hashes and precomputed tables are useless.
Fast hashes let one consumer graphics card try billions of guesses a second. Short passwords fall in minutes. Now switch the storage to bcrypt and keep everything else the same.
The rates are rounded from public hashcat benchmarks on a single RTX 4090. Real attackers use many cards and start with lists of leaked passwords rather than brute force, so real passwords fall much faster than this. The ratio between rows is the point.
What to use in 2026: Argon2id (winner of the Password Hashing Competition in 2015, and OWASP's first choice), or bcrypt with a cost of at least 10 if that is what your platform has, or scrypt. All three include the salt in their output string, so you store one column:
$argon2id$v=19$m=19456,t=2,p=1$c29tZXNhbHQ$wJq3... <- algorithm, settings, salt, hash
$2b$12$R9h/cIPz0gi.URNNX3kh2OPST9/PgBkqquzi.Ss7KIUgO2t0jWMUW <- bcrypt, cost 12Encryption: for data you need back#
Encrypt when you must read the data again: card numbers a payment processor charges later, Aadhaar numbers for KYC, messages, backups, disks. Symmetric encryption (AES) uses one key to lock and unlock and is very fast. Asymmetric encryption (RSA, elliptic curves) uses a public key to lock and a private key to unlock and is much slower. Real systems use both; the details are in symmetric vs asymmetric encryption.
The hard part is never the algorithm. It is the key: where it lives, who can use it, how it rotates. A database encrypted with a key stored in the same database is decoration. Use a key management service (AWS KMS, Google Cloud KMS, HashiCorp Vault) so the application asks for decryption and never holds the master key.
LinkedIn, 2012. About 6.5 million password hashes were posted online; years later the full set turned out to be around 117 million. They were unsalted SHA-1, so most were cracked quickly, and identical passwords had identical hashes.
Adobe, 2013. Around 150 million records. The passwords were encrypted (3DES in ECB mode) instead of hashed, with one key for everyone. Same password, same ciphertext, and the plain text password hints sat right next to them. People solved it like a giant crossword.
| Choice | What you gain | What you pay | Pick it when |
|---|---|---|---|
| Encoding (Base64, URL, hex) | Makes binary data safe for text channels. | Zero secrecy. Anyone can decode it. | Sending images in JSON, tokens in headers, data in URLs. |
| Fast hash (SHA-256, BLAKE3) | Fixed size fingerprint, one way, very fast. | Too fast for passwords. Not reversible, so useless when you need the data back. | Integrity checks, content addressing, HMAC signatures. |
| Password hash (Argon2id, bcrypt, scrypt) | Slow, salted, memory hard. Makes stolen hashes expensive to crack. | Deliberately costs 50 to 250 ms of CPU per login. | Passwords, PINs, API keys you only need to verify. |
| Encryption (AES-GCM, ChaCha20-Poly1305) | Data comes back exactly, for whoever holds the key. | Key management is the whole problem. | Data you must read later: PII, card data, backups, traffic. |
In the interview#
Checkpoint#
1. Why is encrypting passwords worse than hashing them?
2. Why not hash passwords with SHA-256 plus a salt?
3. What does a salt protect against?
- Who gets it back? Encoding: anyone. Hashing: nobody. Encryption: the key holder.
- Base64 is not security. Neither are Kubernetes Secrets by default.
- Passwords: Argon2id or bcrypt, salted, about 100 ms per hash. Never SHA-256, never encryption.
- Encryption's hard part is the key. Use a KMS.
Encoding, hashing and encryption differ in who can get the original back. Encoding, like Base64, only changes the format so data survives a text channel, and anyone can reverse it, so it provides no secrecy. Hashing produces a fixed size fingerprint that cannot be reversed; fast hashes like SHA-256 are for integrity and content addressing, while passwords need deliberately slow, salted hashes like Argon2id or bcrypt so stolen hashes cost an attacker years instead of minutes. Encryption is reversible with a key, used for data you must read again like PII, messages and backups; AES is the symmetric workhorse, and the hard part is key management, which belongs in a KMS. I never encrypt passwords, because one leaked key exposes them all, and the app only ever needs to verify them.