Profile    Mohammed Shiroz Status   Loading  
Logo
Share This
Back to blog
Filter by:
Tags
//Article title

Hashing vs Encryption vs Encoding: The One Question That Tells Them Apart

About Post

"Don't worry, the passwords are encrypted. We base64 them."

That sentence contains two mistakes, and I've heard versions of it more than once. Hashing, encryption and encoding all turn readable data into something that looks like gibberish, so they're easy to mix up. But they answer completely different questions, and using the wrong one is how passwords, tokens and personal data end up exposed.

Let's untangle them for good, with one question that sorts out almost every case.

The one question: who should be able to get the original back?

  • Anyone → that's encoding. The goal is format, not secrecy.
  • Only someone with the key → that's encryption. The goal is confidentiality.
  • Nobody, ever → that's hashing. The goal is verification without storing the original.

Keep that in your head and the rest of this article is detail.

Encoding: changing the format, not hiding anything

Encoding turns data into a different representation so it can travel safely through a system that expects a certain format. Base64 turns binary into plain text characters, so an image can live inside JSON or an email. URL encoding turns a space into %20. UTF-8 turns characters into bytes.

$encoded = base64_encode('secret123');  // "c2VjcmV0MTIz"
$original = base64_decode($encoded);    // "secret123"

There's no key. Anyone can decode it, instantly. That's not a weakness, it's the design.

The classic confusion: a JWT is encoded, not encrypted. Paste one into any JWT decoder and you'll read the payload in plain text. The signature proves it hasn't been changed, but it doesn't hide anything. Never put secrets or sensitive personal data in a JWT payload.

Encryption: secret, but reversible

Encryption scrambles data with a key so that only someone with the right key can turn it back. Use it when you need the original later: an API key for a third-party service, a stored document, data travelling over HTTPS.

The workhorse is AES, a symmetric cipher, meaning the same key encrypts and decrypts. Asymmetric encryption (RSA and elliptic-curve schemes) uses a public key to encrypt and a private key to decrypt, which is what makes things like the TLS handshake possible.

In Laravel, you rarely touch the algorithms directly:

use Illuminate\Support\Facades\Crypt;

$token = Crypt::encryptString($gatewayApiKey);   // safe to store
$apiKey = Crypt::decryptString($token);          // needs APP_KEY

// Or per attribute on a model:
protected function casts(): array
{
    return ['gateway_api_key' => 'encrypted'];
}

Laravel uses AES-256 with a message authentication code, so tampered data fails to decrypt instead of quietly producing garbage. The security of all of it rests on one thing: APP_KEY. Keep it out of Git, back it up, and remember that if you lose it, every encrypted value is lost with it.

Hashing: one way, on purpose

A hash function turns any input into a fixed-length fingerprint. The same input always gives the same output, a tiny change gives a completely different output, and there's no way to compute the input from the output.

That makes hashing perfect for two jobs:

  • Checking integrity. Did this file download correctly? Has this webhook body been changed? SHA-256 is the usual choice, and for webhooks you use an HMAC, a hash mixed with a shared secret, so only the real sender can produce a valid signature.
  • Storing passwords. You never need a user's password back. You only need to check that what they typed matches. So you store a hash and compare hashes.

Why passwords need a special kind of hash

Here's the gotcha that bites even experienced developers: SHA-256 is the wrong tool for passwords, and MD5 is worse.

General-purpose hashes are designed to be fast. That's great for checking files and terrible for passwords, because if your database leaks, an attacker can try enormous numbers of guesses per second against fast hashes.

Password hashing algorithms are deliberately slow and salted:

  • bcrypt: the long-standing default, with a tunable cost factor.
  • Argon2id: a more modern choice that is also memory-hard, which makes attacks with specialised hardware more expensive.
  • A random salt for every password, so two users with the same password get different hashes and precomputed tables are useless.

The good news: you don't implement any of this yourself.

// Plain PHP
$hash = password_hash($password, PASSWORD_DEFAULT);    // bcrypt today
$ok   = password_verify($input, $hash);

// Laravel
$hash = Hash::make($password);
$ok   = Hash::check($input, $hash);
if (Hash::needsRehash($hash)) { /* re-hash after a successful login */ }

The salt and the algorithm settings are stored inside the hash string itself, so there's no separate column to manage. One detail worth knowing: bcrypt only uses the first 72 bytes of the input, so very long passphrases are silently truncated. Argon2id doesn't have that limit.

The cheat sheet

EncodingEncryptionHashing
PurposeFormat and transportConfidentialityVerification and integrity
Reversible?Yes, by anyoneYes, with the keyNo
Needs a key?NoYesNo (HMAC uses a secret)
ExamplesBase64, URL encoding, UTF-8AES, RSA, TLSSHA-256, bcrypt, Argon2id
Use it forBinary in JSON, URLs, emailsAPI keys, sensitive stored dataPasswords, checksums, signatures

Common confusions, corrected

  • ❌ "Base64 encrypted." ✅ Base64 is encoding. It hides nothing.
  • ❌ "We encrypt passwords." ✅ Passwords should be hashed with bcrypt or Argon2id, so even you can't read them.
  • ❌ "Let me decrypt the hash." ✅ Hashes can't be decrypted. "Cracking" a hash means guessing inputs until one matches, which is exactly what slow hashes are built to resist.
  • ❌ "SHA-256 is secure, so it's fine for passwords." ✅ Secure for integrity, too fast for passwords.
  • ❌ "The JWT is safe to put anything in." ✅ It's signed, not encrypted. Anyone can read it.

If you remember one thing: ask who should be able to get the original back. Anyone: encode. Only the key holder: encrypt. Nobody: hash, and for passwords, use a slow password hash through your framework.

Which of these confusions have you run into most in code reviews? I'd love to hear the most creative "encryption" you've ever found in a codebase.

Comments (0)
Leave your review

Thanks for your valuable comments. Your comments has been updated and appreciate your getting in touch...

01. About Shiroz

Mohammed Shiroz

Hi, I'm Mohammed Shiroz, a software engineer and AI enthusiast from Sri Lanka who turns ideas into intelligent, real-world solutions. With over 9 years of hands-on experience, I currently lead real estate ERP development at Kate Group, a...

03.My Projects

04. Categories

Ready To order Your Project ?

Get in Touch
Close