These three get used interchangeably in conversation and they are not remotely the same thing. The confusion is not academic: it is how credentials end up sitting in plain sight in a config file, and how password databases end up crackable in an afternoon.
The distinction in one table
| Reversible? | Needs a key? | For | |
|---|---|---|---|
| Encoding | Yes, by anyone | No | Making data survive transport |
| Hashing | No, ever | No | Proving something is unchanged |
| Encryption | Yes, with the key | Yes | Keeping something secret |
Read the first column and you have most of it. Only encryption keeps a secret. Encoding keeps none, and hashing does not keep the data at all.
Encoding: not security, at all
Encoding rewrites data into a different alphabet so it can travel somewhere that would otherwise mangle it. Base64 exists because email and URLs were built for text, and raw binary put through them arrives corrupted — so the bytes are re-expressed using 64 safe characters.
There is no key and no secret. cGFzc3dvcmQxMjM= looks scrambled and takes about one second to turn back into password123. Anyone can do it; that is the whole design.
Base64 is not encryption. If you find credentials “protected” by Base64 in a config file or a request header, they are stored in plain text with extra steps. This is a genuinely common and genuinely serious mistake.
Useful for: embedding a small image in CSS, putting binary in JSON, inspecting a payload. Never for: keeping anything private.
JWTs catch people out for exactly this reason
A JSON Web Token looks encrypted. It is not — the standard ones are Base64-encoded JSON with a signature attached. Anyone holding the token can read every claim inside it, which you can confirm by decoding one without supplying any key at all.
The signature stops it being modified, not read. Never put anything in a JWT you would not hand to the bearer.
Hashing: a one-way fingerprint
A hash function takes any input and produces a fixed-length string. The same input always gives the same output; changing a single character changes the output completely. Crucially, there is no way back — the original is not in there to recover.
That one-way property is what makes it useful:
- Verifying a download. Hash the file you received and compare with the publisher’s. Match means byte-identical.
- Storing passwords. A service stores the hash, not the password. At login it hashes what you typed and compares. A stolen database yields hashes, not passwords.
- Detecting change. Deduplication, caching, integrity checks.
“Decrypt this hash” is not a thing
You cannot. A hash of a 5GB file is 64 characters — the information is not compressed, it is discarded. What sites offering to “reverse a hash” actually do is look it up in a table of pre-computed hashes of common inputs. If your password is in that table, they find it. That is a dictionary attack, not decryption, and it is exactly why password hashing needs a salt.
Which hash to use
- MD5 — broken for security. Collisions can be produced deliberately, so it proves nothing about authenticity. Fine as a checksum against accidental corruption, and still widely used for that.
- SHA-1 — also broken, demonstrated in practice. Do not choose it for anything new.
- SHA-256 — the sensible default for integrity and signatures.
- bcrypt, scrypt, Argon2 — for passwords, and only these. They are deliberately slow, which is the point: SHA-256 is fast enough to try billions of guesses per second, and these are not.
That last one is the mistake worth avoiding. Hashing passwords with SHA-256 is better than plain text and much worse than bcrypt, because the speed that makes SHA-256 good at checksums makes it bad at resisting guessing.
Encryption: the only one that keeps a secret
Encryption transforms data so it can be transformed back — but only by someone holding the key. It is the only one of the three that actually protects confidentiality.
- Symmetric (AES) — one key both encrypts and decrypts. Fast; the difficulty is getting the key to the other party.
- Asymmetric (RSA, elliptic curve) — a public key encrypts, a private key decrypts. Slower, and solves the key-sharing problem. HTTPS uses asymmetric to agree a symmetric key, then switches.
The security is entirely in the key, never in the algorithm. Good algorithms are public and heavily studied; an algorithm kept secret because it would not survive inspection is the classic warning sign.
Where signing fits
HMAC is hashing plus a key, which answers a question a plain hash cannot: not only “is this unchanged” but “was it written by someone holding the secret”. It is what webhook providers use to sign payloads.
Note that HMAC is not simply hash(key + message). That construction is vulnerable to length-extension attacks, where someone who never sees the key can still append to the message and produce a valid digest. HMAC’s nested design exists specifically to prevent it — which is a good illustration of why you use the standard primitive rather than assembling your own.
The short version
- Anyone can decode encoding. It protects nothing.
- Nobody can reverse hashing. It proves sameness, it does not store data.
- Only the key-holder can decrypt encryption. It is the only one that hides anything.
- Hash passwords with bcrypt or Argon2, never SHA-256, never MD5.
- Assume anything in a JWT is public.