· 3 min read · 709 words
Hashing, Encryption and Encoding Are Not the Same Thing
Base64 is not encryption, encryption is not hashing, and passwords need exactly one of the three. How to tell them apart, and the specific failure each mix-up produces.
- hashing
- encryption
- basics
These three get used interchangeably in bug reports, in tickets and occasionally in code review comments, and the mix-up is not harmless. Each one exists for a different reason and the wrong choice fails in a different way.
Encoding changes the alphabet, nothing else
Base64, hex, URL encoding, quoted-printable. All of them rewrite data into a character set that survives whatever pipe it is about to go through. There is no key and no secret, and anybody can undo it because undoing it is the entire point.
btoa('hunter2'); // 'aHVudGVyMg=='
atob('aHVudGVyMg=='); // 'hunter2'A password stored base64 encoded is a password stored in plaintext with an extra step. Every so often this turns up in a breach and gets reported as encrypted credentials, which it is not.
Encryption is reversible on purpose, with a key
AES, ChaCha20, RSA. You encrypt because you need the original back later, and the key is what decides who gets it. Take the key away and the ciphertext is useless, which is the property everything else depends on.
That property is also the problem. The key has to exist somewhere your application can reach, which usually means the same servers, the same environment variables, sometimes the same repository. An attacker who copied your database is often in a position to copy the key too.
Hashing throws the input away
SHA-256, bcrypt, Argon2. Data goes in, a fixed size digest comes out, and there is no key because there is no way back. Not a difficult way back, not an expensive one. The information is gone, and the only route to the original is guessing inputs until one produces the same digest.
That is what makes it right for passwords. You never need to see the password again. You only need to answer one question, which is whether the string somebody just typed is the same one they typed when they signed up, and recomputing the digest answers it.
| Encoding | Encryption | Hashing | |
|---|---|---|---|
| Reversible | yes, by anyone | yes, with the key | no |
| Needs a secret | no | yes | no |
| Output size | grows with input | grows with input | fixed |
| Point of it | safe transport | get it back later | never get it back |
| For passwords | no | no | yes, a slow one |
The tell: can the site show you your own password?
If a service can email you your existing password, it did not hash it. It either encrypted it or stored it as it came in, and either way one incident hands over every account at once. A password reset link is what a correctly built system can offer, because it genuinely cannot read what you chose.
The same test applies to your own code. Anywhere you can print the plaintext of a stored credential is a place where hashing was skipped.
Which is why bcrypt cannot be decrypted
The single most common search around this subject is some form of bcrypt decrypt, and there is no tool that does it, including this one. What people usually want is either to check a password against a hash, which the verifier does, or to replace a forgotten hash with a new one, which the generator does. There is a longer version of that answer on the bcrypt decrypt page.
Not everything is a password
The distinction matters most when you have data that is sensitive but that you genuinely need to read back. API credentials for a third party, bank details, a document somebody uploaded. Those get encrypted, with the key held somewhere the database dump does not reach, and with a plan for rotating it.
Passwords are the case where you can give up readability entirely, and giving it up is the strongest thing you can do. Use it. Then pick a hash that is deliberately slow, because a fast one gives you a different problem.
Fast digests still have their place. Checksums, deduplication, content addressing, signature inputs. That is what SHA-256 is for, and none of those jobs involve a human choosing the input.
The short form
- Encoding: reversible by anyone, use it for transport.
- Encryption: reversible with a key, use it when you need the data back.
- Fast hashing: not reversible, use it for integrity checks.
- Slow hashing: not reversible and deliberately expensive, use it for passwords.