Security 5 min read · 8 August 2026

Hashing, encryption and encoding are three different things

They get used interchangeably in conversation and they are not remotely interchangeable in practice. Confusing two of them is behind a large share of real security failures.

Three words that get swapped freely in conversation and mean completely different things. The confusion is not academic: "we encrypted the passwords" and "we hashed the passwords" describe different systems with different consequences when one is breached, and "we encoded it" describes no security at all.

Encoding: changing the format

Encoding converts data from one representation to another so that some system can carry it. Base64 turns arbitrary bytes into 64 safe characters so binary can travel through channels that only accept text. URL encoding turns a space into %20 so a URL stays parseable. UTF-8 turns characters into bytes.

There is no key and no secret. The scheme is public and the whole point is that anyone can reverse it — that is what makes it useful. Encoding is about compatibility, not confidentiality.

Which is why "the password is Base64 encoded" is not a security measure but a description of the file format. Anyone can paste it into a Base64 decoder and read it, and that is not a flaw in Base64. It is what Base64 is for.

The mistake shows up regularly in real systems: HTTP Basic authentication sends credentials Base64-encoded, and people see the gibberish and assume it is protected. It is not. Over plain HTTP those credentials are readable by anyone on the path. TLS is what protects them; the Base64 is packaging.

Encryption: reversible, with a key

Encryption transforms data so it cannot be read without a key, and can be perfectly recovered with one. Two-way, by design.

Two families. Symmetric encryption — AES being the one you will meet — uses the same key to encrypt and decrypt. It is fast and it is what protects data at rest: disk encryption, database fields, encrypted backups. The hard part is not the algorithm, it is getting the key to the other party without it being intercepted.

Asymmetric encryption — RSA, and increasingly elliptic-curve schemes — uses a key pair. Anything encrypted with the public key can only be decrypted with the private one. That solves key distribution, since the public key can be published, and it is what underlies TLS certificates and signed messages. It is also much slower, which is why TLS uses asymmetric cryptography only to agree a symmetric key, then switches.

Use encryption when you need the original back: card details you must charge later, messages the recipient must read, files that have to be restored.

Hashing: one-way, on purpose

A hash function takes input of any size and produces a fixed-size output. SHA-256 always produces 256 bits, whether the input is one character or a gigabyte.

The defining property is that it is not reversible. Not "hard to reverse" — there is no inverse function, because information has been destroyed. Infinitely many inputs map to any given 256-bit output; the hash cannot tell you which one you started with.

Good hash functions also guarantee:

  • Determinism. The same input always gives the same output.
  • Avalanche. Change one bit of input and roughly half the output bits change. Similar inputs do not produce similar hashes, so you can learn nothing about the input by comparing hashes.
  • Collision resistance. Finding two inputs with the same hash should be computationally infeasible. MD5 and SHA-1 have both failed this test and are broken for any security purpose because of it.

Use hashing when you never need the original: verifying a password without storing it, checking a downloaded file is intact, detecting whether a document changed.

The distinction that matters most

Passwords must be hashed, never encrypted.

Encryption implies a key, the key must live somewhere your application can reach, and anyone who breaches the application usually reaches the key too. A breach then yields every password in plaintext.

Hashed passwords have no key to steal. Verification works by hashing what the user typed and comparing — the system never needs to know the original, and neither does an attacker who takes the database.

And a further point people miss: a general-purpose hash is not enough either. SHA-256 is designed to be fast, which is exactly wrong for passwords, because fast means an attacker can try billions of guesses per second. Password hashing needs a deliberately slow function — bcrypt, Argon2, scrypt — with a per-user salt. That is a large enough topic to have its own guide.

HMAC: the one that combines two of them

An HMAC is a hash computed with a secret key mixed in. It answers a question a plain hash cannot: did this come from someone who knows the secret, and has it been altered?

A plain hash proves integrity only if the hash itself arrived through a trusted channel — otherwise an attacker who changes the message simply recomputes the hash. An HMAC cannot be recomputed without the key, so it proves integrity and authenticity together.

This is what signs webhooks, API requests and JWTs. When Stripe or GitHub sends your server an event, the signature header is an HMAC — you recompute it with your shared secret and compare. If it matches, the payload is genuine and unmodified.

One detail with real consequences: compare HMACs in constant time. A normal string comparison returns as soon as it finds a difference, and the timing of that return leaks how many leading bytes were correct. Repeated enough, that recovers the signature. Every language has a constant-time comparison function for exactly this; use it.

Our HMAC generator computes them with the common algorithms if you need to verify a webhook signature by hand while debugging.

Choosing, in one line each

  • Need the data back, need it secret → encryption
  • Never need the data back, only need to check a match → hashing
  • Need to check a match on a password specifically → slow password hashing, not SHA-256
  • Need to prove a message is genuine and unmodified → HMAC or a digital signature
  • Need to move data through a system that mangles it → encoding, and understand it protects nothing

The tell-tale mistakes

"We encrypt passwords." Either a wording slip or a real architectural problem. Worth asking which.

"It's encoded so it's safe." It is not. Encoding is reversible by anyone by definition.

MD5 or SHA-1 for anything security-related. Both have practical collision attacks. MD5 remains fine as a non-security checksum for accidental corruption — our MD5 generator exists for exactly that, verifying a file matches a published checksum — and it must not be used where an adversary is involved.

Writing your own crypto. The algorithms are public and the implementations are the hard part: timing, padding, key handling, randomness. Every widely used language has a vetted library. Use it.

More guides

Stay Updated

Get the latest tools, AI features, and product updates. No spam.