"The passwords were encrypted." "The token is encoded, so it's secure." "Just hash the credit card number." Statements like these show up in code reviews, vendor documentation and breach notices, and each one mixes up three very different things.
Encoding, hashing and encryption all turn data into something that looks scrambled. The difference is what it takes to get the original back: for encoding, nothing; for hashing, it's impossible by design; for encryption, a key. That one question decides which to use.
The same message, three ways
Here's the text Meet at 7pm run through each one:
| Method | Output |
|---|---|
| Encoding (Base64) | TWVldCBhdCA3cG0= |
| Hashing (SHA-256) | a08301f7df29148bd2b8a8a77214f55da5818af882c0fd50e3fee5b903216d95 |
| Encryption (AES-256-GCM), run 1 | dLbFZHZKHIpY9cWGDU5OU7U8NGA/qtGCr1OV |
| Encryption (AES-256-GCM), run 2 | tGh2UWGFLauEFtufwpYnPCWiZQOOg3logz1x |
The Base64 and SHA-256 values come out the same every time, for anyone, on any computer. You can reproduce them in our Base64 Encoder and SHA Generator. The two encryption results are different because each run used a new random key and a new random starting value. Without the key, neither can be turned back into the message. With it, both decrypt to Meet at 7pm.
Encoding: changing the format
Encoding converts data into another representation so that a particular system can carry or display it. It uses a public, fixed set of rules and no secret. Anyone who knows the scheme can reverse it, and the scheme is usually obvious.
Common examples:
- Base64 turns bytes into text-safe characters for email, JSON and data URLs (RFC 4648). Our guide What Is Base64 Encoding? walks through how it works.
- URL encoding turns a space into
%20so it can go inside a URL, as our URL Encoder does. - HTML entities turn
<into<so a browser shows the character instead of treating it as a tag. - UTF-8 turns characters into bytes in the first place.
Encoding is about compatibility, never secrecy. If you can read the format's name, you can decode it.
Hashing: a one-way fingerprint
A cryptographic hash function turns input of any size into a fixed-size digest. SHA-256, specified in NIST FIPS 180-4, always produces 256 bits. Three properties make it useful:
- Deterministic: the same input always gives the same digest.
- One-way: there's no way to compute the input from the digest. The only approach is to guess inputs and compare.
- Sensitive to change:
Meet at 8pmhashes toeff8250b79f4…, nothing like the digest forMeet at 7pm.
That makes hashes ideal for checking that something hasn't changed, such as a downloaded file, and for identifying content without storing it. It's also the basis of password storage: a site stores a hash and checks it at login, so it never needs to keep the password itself.
There's an important caveat for passwords. General-purpose hashes like SHA-256 are fast, which lets attackers test enormous numbers of guesses against a leaked database. Passwords need a deliberately slow, salted password hash such as Argon2id or bcrypt. MD5 vs SHA-256 vs bcrypt covers that in detail.
"Hash decryption" sites don't break hashes. They look up digests of known inputs, which only works for common or short values.
Encryption: reversible, with a key
Encryption transforms data so that only someone with the right key can turn it back. It's the only one of the three that provides confidentiality.
- Symmetric encryption uses the same key to encrypt and decrypt. AES, standardized in FIPS 197, is the standard choice. The OWASP Cryptographic Storage Cheat Sheet recommends AES "with a key that's at least 128 bits (ideally 256 bits)" in an authenticated mode such as GCM.
- Asymmetric (public-key) cryptography uses a key pair: a public key anyone can have and a private key only the owner holds. HTTPS uses it to verify the server and agree on a shared key with a server you've never talked to before, then both sides switch to fast symmetric encryption.
Authenticated modes like GCM do two jobs: they keep the data secret, and they detect tampering. In the example above, the 11-byte message became 27 bytes because GCM adds a 16-byte authentication tag. Change a single bit of the ciphertext and decryption fails instead of producing garbage.
Encryption is only as strong as the key handling. OWASP's advice is concrete: don't hard-code keys in source code, don't commit them to version control, and use a proper secrets store where one is available.
Side by side
| Encoding | Hashing | Encryption | |
|---|---|---|---|
| Purpose | Compatibility | Integrity, fingerprinting, password checks | Confidentiality |
| Reversible? | Yes, by anyone | No | Yes, with the key |
| Uses a secret? | No | No (HMAC adds a key) | Yes |
| Same input, same output? | Yes | Yes | No, with a modern mode |
| Output size | Depends on input | Fixed | About the input size, plus overhead |
| Examples | Base64, URL encoding, UTF-8 | SHA-256, SHA-3, bcrypt, Argon2id | AES-GCM, ChaCha20-Poly1305, RSA |
Which one do you need?
- Storing user passwords: a password hash (Argon2id, scrypt or bcrypt). Never encryption, because you never need the password back, and never plain encoding.
- Storing data you'll need to read later, like API tokens for third-party services or personal data: encryption, with the key kept separately from the data.
- Checking a file wasn't corrupted or altered: a hash such as SHA-256, compared with a value from a trusted source.
- Proving a message came from someone with a shared secret, as with webhook signatures: HMAC, which combines a hash with a key.
- Putting binary data in JSON, a URL or an email: encoding. Add encryption first if the data is sensitive.
Encoding and encryption often appear together. Encrypted data is raw bytes, so it's usually Base64-encoded afterward to store or send as text, which is why the ciphertexts in the first table are shown in Base64. The encoding doesn't add or remove any security.
How to tell what you're looking at
When you find an unfamiliar string in a database or a config file, its shape usually gives it away:
- Letters, digits,
+and/, often ending in=: probably Base64. Try decoding it. If readable text comes out, it was only encoded. - Exactly 32 hex characters: likely an MD5 digest. 64 hex characters: likely SHA-256.
- Starts with
$2a$,$2b$or$2y$: a bcrypt hash.$argon2id$: an Argon2id hash. - Random-looking bytes or Base64 that decodes to gibberish, different every time for the same value: probably encrypted.
These are clues, not proof, but they're usually enough to know whether you're dealing with something anyone can read.
Common mix-ups to watch for
- "The password is encrypted in Base64." Base64 is encoding. Anyone can decode it.
- "We encrypt passwords with MD5." MD5 is a hash, not encryption, and it's the wrong hash for passwords.
- "The data is in a JWT, so it's secure." A standard JWT is signed, not encrypted. Its payload is Base64url-encoded JSON that anyone can read.
- "We hashed the card numbers, so they're anonymized." Card numbers follow a known structure, and many digits are predictable, so unsalted hashes of them can be found by trying candidates. Use encryption or tokenization.
FAQ
Is hashing a type of encryption?
No. Encryption is designed to be reversed with a key. Hashing is designed never to be reversed.
Can encoded data be secure?
Only if it was encrypted before it was encoded. Encoding itself hides nothing.
Why does encryption give a different result each time?
Modern modes use a random or unique starting value (an IV or nonce) for each message, so the same plaintext never produces the same ciphertext twice. That stops attackers from spotting repeated messages.
Where does HMAC fit?
HMAC is a hash combined with a secret key. It proves that a message wasn't changed and came from someone who knows the key, but it doesn't hide the message.