Skip to content
New

DeepSeek V4.1 Flash free for 7 days: 10M tokens a day after any top-up. Until Nov 30.

How it works

Encryption vs Encoding vs Hashing: What Each One Does

Separate encoding, encryption and hashing with Base64, SHA-256 and OpenSSL labs. Learn why Base64 is not protection and hashes are one-way.

Beginner9 min readBy NotHoly

Encoding, encryption and hashing all turn data into something else, which is why people mix them up. They have different goals. Encoding changes how data is written down, so anyone can reverse it. Encryption hides data from people who do not hold a key, and you can reverse it with that key. Hashing produces a short fingerprint that you cannot turn back into the original input. If you remember one sentence: Base64 is not encryption, and a hash hides nothing about short inputs.

This article separates the three ideas, then asks you to run each one in a terminal on the same text. You will compare the results yourself.

Start here

You need a terminal with base64, sha256sum and openssl. On Windows 11 the commands below run in Git Bash, which ships with Git for Windows. A PowerShell version of the hashing step is included. You do not need prior cryptography knowledge, but reading the Caesar cipher article first helps with the idea of a key.

Every command in the lab is safe to run on your own machine. Use a test file, not a real secret.

Three different jobs

The three operations answer three different questions.

Operation Question it answers Needs a key? Can be reversed?
Encoding How do I represent these bytes as text or in a format another system expects? No Yes, by anyone
Encryption Who can read this data? Yes Yes, by holders of the right key
Hashing Did this data change, or do two values match? No No, by design

Keep this table in mind during the lab. The rest of the article explains each row.

Encoding changes the representation

Encoding rewrites data in another form so that a system can carry it. Base64 is the classic example. It takes bytes and writes them using 64 printable characters: A to Z, a to z, 0 to 9, + and /, with = used for padding. RFC 4648 defines the format. Email attachments, data URLs and many API payloads use it because the transport expects text.

Base64 has no secret. The mapping is public and fixed. Any tool that knows the rule can turn the output back into the input. That is the purpose of encoding: interoperability, not secrecy.

Encryption hides data behind a key

Encryption takes readable data, called plaintext, and transforms it with an algorithm and a key into ciphertext. Someone without the key should learn nothing useful from the ciphertext. Someone with the key can decrypt it.

There are two families. Symmetric encryption uses the same secret key for encrypting and decrypting. AES is the common choice. Asymmetric encryption uses a public key and a private key. This article uses symmetric encryption, because the OpenSSL command in the lab does too.

Good encryption depends on more than the algorithm. You must choose a safe mode, generate keys with a good random source, and protect the key. The OpenSSL command in the lab uses a password and PBKDF2 to derive the key. OpenSSL's help text says PBKDF2 uses 10,000 iterations by default unless you change it with -iter.

Hashing creates a fingerprint

A cryptographic hash function takes input of any length and returns a fixed-length output. SHA-256 is specified in FIPS 180-4, and its output is always 256 bits, written as 64 hexadecimal characters. Two properties matter for beginners:

  • The same input always gives the same output.
  • A small change in input should change the output so much that it looks unrelated. Good hash functions are designed so that finding two inputs with the same output is infeasible.

Hashing is one-way. Nothing in the output tells you the original text. You can check whether a candidate input produces a known hash. You cannot recover the input from the hash alone, except by guessing and testing.

Note that a hash is a fingerprint, not a lock. Anyone can compute the SHA-256 of a public file. A hash proves that two copies match. It does not hide the file.

Why this matters

Most real security mistakes in this area come from using the wrong tool for the job.

  • A developer stores an API key in Base64 and calls it "encrypted." Anyone who sees the value can decode it in one command.
  • A team checks a download with a hash, but the hash is published on the same page as the file, served by the same compromised server. The check proves the file matches the page, nothing more.
  • A web app stores passwords with plain SHA-256. A stolen database can be attacked quickly with guesses, because SHA-256 is designed to be fast. OWASP's cryptographic storage guidance says that passwords should be protected with secure password hashing algorithms instead of reversible encryption, and points to its Password Storage Cheat Sheet for the details. Slow, salted password hashes such as Argon2id, scrypt, bcrypt or PBKDF2 are the usual choices. The next article in this series covers Argon2id.

Learning the difference early saves you from these traps.

Lab 1: Encoding with Base64

Open Git Bash in an empty folder. Encode a short phrase, then decode the result.

bash
echo -n 'hello lab' | base64

The output I got on this machine with OpenSSL 3.2.4 and Git Bash:

text
aGVsbG8gbGFi

Now decode that output:

bash
echo -n 'aGVsbG8gbGFi' | base64 -d

Output:

text
hello lab

Two things to notice. First, no key was involved. Second, echo -n matters. Without -n, echo adds a newline, and the Base64 output changes. Run echo 'hello lab' | base64 and compare: I got aGVsbG8gbGFiCg==. Base64 turns 9 bytes into 12 characters here, so the output is longer than the input.

Ask yourself: could someone without any secret reverse this? Yes. That is the test that separates encoding from encryption.

Lab 2: Hashing with SHA-256

Run the same phrase through SHA-256:

bash
echo -n 'hello lab' | sha256sum

Output:

text
8fc6baba79a0d60b37dee612ccc1ec096ef52dba8cb0a24a6451e8bfb0e4d761 *-

Now add one exclamation mark and run it again:

bash
echo -n 'hello lab!' | sha256sum

Output:

text
36902fb7fdea33458ad09dfeb52118dc47f99a8ca2b9001080366d55511de915 *-

The two hashes share no visible pattern. One character changed the whole output. Both are 64 hexadecimal characters, which is 256 bits.

The - at the end means the input came from standard input, not a file. The * before it is the binary-mode marker that Git Bash's sha256sum prints. Other systems may print two spaces instead, and the hash is the same. The hash of a file works the same way.

Hash a file and detect a change

Create a small file and hash it:

bash
echo 'secret note' > note.txt
sha256sum note.txt

On my machine, with Unix line endings in the file, the output was:

text
b5f891a5e064fec661025d0b0ec2de157487a6c2e5cc46dc0971fee56f86c645 *note.txt

Change the file, even a single character, and hash it again. The value will differ. That is how integrity checks work. The check tells you that the file changed. It does not tell you what changed, and it does not stop an attacker from changing both the file and the published hash.

Windows PowerShell alternative

If you prefer PowerShell, Windows has a built-in command:

powershell
Get-FileHash note.txt -Algorithm SHA256

Check the output for the Hash line, which shows 64 hexadecimal characters. The hash depends on the exact bytes in the file. PowerShell's Set-Content writes Windows line endings (CRLF), which differ from the LF ending in the Bash example above. On my machine, a file written this way gave this hash:

text
406A5646AE75CA75D032F306ABD33085DC9F656E3109BB962AEAB335EEC9ED85

The same bytes hashed with sha256sum in Git Bash gave the same value in lowercase. If your hash differs from the Bash example but matches the PowerShell result for your own file, the line endings are the reason.

Lab 3: Encrypting a file with OpenSSL

Create a note and encrypt it with AES-256-CBC. OpenSSL will ask you for a password. Choose one you will remember and use only for this lab.

bash
echo 'secret note' > note.txt
openssl enc -aes-256-cbc -pbkdf2 -salt -in note.txt -out note.enc

OpenSSL prompts for the password, and the encrypted file is written to note.enc. The -salt option adds a random salt, so encrypting the same file twice gives different output. An encrypted file made with -salt begins with the ASCII text Salted__. I checked this on my machine. The rest of the file is binary and unreadable.

Now decrypt it:

bash
openssl enc -d -aes-256-cbc -pbkdf2 -in note.enc

Enter the same password. Output:

text
secret note

Decryption only works with the right password. I tested with a wrong one. OpenSSL printed bad decrypt and exited with an error.

Encryption does not detect tampering by itself

Next, change one byte of the encrypted file and try to decrypt it. I flipped one bit inside the ciphertext block of a copy named tampered.enc. Decryption failed with bad decrypt, and the command exited with status 1.

This failure is a lucky accident of CBC padding. Other changes can produce garbage output without an error. The lesson is that plain encryption does not give you a reliable signal that the ciphertext was modified. Systems that need both secrecy and integrity use authenticated encryption, such as AES-GCM, or add a message authentication code. That is an advanced topic, but it explains why an encrypted file is not automatically a trusted file.

Putting the three side by side

Run the same text through each operation and compare:

Operation Command Output on hello lab (observed)
Encoding echo -n 'hello lab' | base64 aGVsbG8gbGFi
Hashing echo -n 'hello lab' | sha256sum 8fc6baba...e4d761
Encryption openssl enc ... -in note.txt Binary data, needs the password to read

Ask what each output lets you do:

  • Base64 lets anyone recover hello lab.
  • The hash lets you verify that a candidate input is hello lab, but not recover the input from the hash alone.
  • The encrypted file lets you recover secret note only with the password.

Common mistakes

Calling Base64 "encryption" or "obfuscation" for secrets. Base64 hides nothing. Anyone who sees a Base64 string can decode it. Store secrets in a secrets manager or an encrypted store, not in encoded form.

Using a hash as a lock. A hash is one-way, but short or common inputs can be guessed. Hash hello lab and an attacker with a list of common phrases recovers it without breaking SHA-256. This is why password hashing needs salts and slow algorithms.

Using plain SHA-256 for passwords. SHA-256 is fast by design, which suits file checksums and is a poor fit for password storage. Use a password hashing function built for the job.

Trusting a hash from the same place as the file. A checksum on the same compromised page proves nothing. Get the expected hash through a separate, trusted channel, or verify a digital signature.

Forgetting that encryption needs key management. The lab uses a password typed into a prompt. Real systems must store, rotate and protect keys. Losing the key means losing the data.

Writing your own cryptography. Use established libraries and protocols. The lab commands are for learning, not a template for production systems.

How to go further

Repeat the three labs with a different phrase, then with a file of a few kilobytes. Notice that the Base64 output grows by about a third, the hash stays 64 characters, and the encrypted file grows only by the header and padding.

Next, read about password hashing. The problem there is not hashing as such, but the cost of guessing. The next article in this series, How Password Hashing Works with Argon2id, explains salts, work factors and why slow hashes matter. If you want a refresher on the cipher side first, read Caesar Cipher in Python. It shows a key and an algorithm in a form you can test.

When you study real protocols, look for three things in each design: what it encodes, what it encrypts, and what it hashes. Most confusion disappears once you ask which of the three jobs each part is doing.

Sources

Sources

  1. RFC 4648: The Base16, Base32, and Base64 Data Encodings
  2. FIPS 180-4: Secure Hash Standard (SHS), with update 1
  3. OWASP Cryptographic Storage Cheat Sheet

More in Cryptography

Cryptography

Passwords and Hashing with Argon2id

Why fast hashes fail for passwords, what salts and work factors do, and how to hash and verify with Argon2id in Python using argon2-cffi.

Intermediate10 min read