The one-line distinction
| Operation | Reversible? | Needs a key? | Purpose |
|---|---|---|---|
| Encode | Yes, trivially | No | Make data fit a channel (Base64, percent-encoding) |
| Hash | No, by design | No | Prove content is unchanged; store a verifier instead of a secret |
| Encrypt | Yes, with the key | Yes | Keep data secret from everyone without the key |
Encoding hides nothing: Base64 is decoded by anyone in one step. Hashing cannot be undone at all — that is the whole point. Encryption is the only one that protects confidentiality, and it is the only one that needs a secret to work.
Hashing: one-way by construction
A cryptographic hash takes any input and produces a fixed-length digest — SHA-256 always gives 256 bits, whether you hashed one byte or one gigabyte. Three properties make it useful:
- Deterministic. The same input always gives the same digest.
- Preimage-resistant. You cannot go from digest back to input.
- Collision-resistant. Finding two inputs with the same digest is computationally infeasible (for a modern hash).
That is exactly what you want for integrity. Download a file, hash it, compare against the published digest: if they match, the file is byte-for-byte what the publisher hashed. The file hash tool does this locally, which is the right place — uploading a file to check its integrity defeats half the purpose.
“Can you decrypt this hash?”
No. There is no key and no inverse. When a service claims to “decrypt” a hash, it is doing one of three things: it is actually encrypting, it keeps a lookup table of common inputs, or it is brute-forcing. The last two are the important ones.
A hash of a low-entropy input is not secret. Passwords are the canonical example: there are only so many human-chosen passwords, so an attacker hashes a list of billions of candidates and looks up matches. A rainbow table is a precomputed version of the same idea. This is why a plain SHA-256 of a password is a bad design even though SHA-256 is a perfectly good hash.
Password hashing is a different job
Passwords need a hash that is deliberately slow and salted, so that guessing is expensive and a precomputed table does not help:
| Use | Right tool | Why |
|---|---|---|
| File integrity, checksums, content addressing | SHA-256 / SHA-512 | Fast is a feature |
| Password storage | Argon2id, scrypt, bcrypt, PBKDF2 | Slow by design, salted, tunable cost |
| Message authentication (is this really from them?) | HMAC-SHA-256 | A hash bound to a secret key |
| Signatures with public verification | Ed25519, ECDSA, RSA-PSS | Verify without sharing the signing key |
A salt is a random value stored alongside each hash and mixed into the input. It does not make the password stronger; it makes the attacker's precomputation useless and prevents two users with the same password from having the same stored value. The iteration count (or memory cost) is the dial that makes each guess expensive — Argon2id is the current recommendation because it also resists GPU and ASIC attacks by requiring memory.
Encryption: the only reversible one
Encryption uses a key. Symmetric encryption (AES-GCM, ChaCha20-Poly1305) uses the same key to encrypt and decrypt; asymmetric encryption (RSA, ECIES) uses a public key to encrypt and a private key to decrypt. Two things are easy to get wrong:
- Use authenticated encryption. AES-GCM and ChaCha20-Poly1305 both include an authentication tag, so tampering is detected. AES-CBC without a MAC is malleable: an attacker can flip bits in the ciphertext and produce predictable changes in the plaintext.
- Never reuse an IV/nonce with the same key. With GCM, nonce reuse is catastrophic — it can leak the authentication key outright. Generate a fresh random nonce per message.
The text encryption tool on this site uses AES-256-GCM with PBKDF2-HMAC-SHA-256 at 600,000 iterations, generates a fresh salt and IV per message, and packages them into a self-describing envelope. The passphrase and key are never stored or transmitted.
Where each one belongs
| You want to… | Use | Do not use |
|---|---|---|
| Check a download is intact | SHA-256 | Base64, MD5 |
| Store user passwords | Argon2id / bcrypt | SHA-256, MD5, encryption |
| Send data through a JSON API | Base64 | Encryption (unless it must be secret) |
| Keep a note private on your own device | AES-256-GCM with a strong passphrase | Hashing (you cannot read it back) |
| Compare two secrets | Constant-time comparison | Plain ===, hashing then comparing |
| Sign a message so others can verify | Ed25519 / ECDSA, or HMAC if both sides share a key | A bare hash |
The mistakes that follow from mixing them up
- “Encrypting” with Base64. Storing credentials Base64-encoded is storing them in plaintext with extra steps.
- Hashing a password with SHA-256 because it is “secure”. Fast hashes are the wrong tool for passwords; GPU-accelerated guesses run into the billions per second.
- Encrypting when you meant to hash. If the server can decrypt stored passwords, a database leak hands the attacker every password.
- Hashing when you meant to encrypt. Hashing a value you need to read back is unrecoverable — people discover this after a migration.
- Comparing hashes with
==. For secrets, use a constant-time compare; early-exit equality leaks how many bytes matched.
A good rule: name the operation out loud before writing the line. “I am hashing this so I can check it later without storing it” and “I am encrypting this so only I can read it” lead to different APIs, and saying which one you mean catches most of these before they ship.
Which hash algorithm, in 2026
Algorithm choice is one of the few places where the answer is unambiguous. The shortlist:
| Algorithm | Status | Use for |
|---|---|---|
| SHA-256 / SHA-512 | Recommended | Integrity, checksums, content addressing, HMAC |
| SHA-3 | Recommended | Where a sponge construction is preferred; not needed to replace SHA-2 |
| BLAKE2 / BLAKE3 | Recommended | Speed-sensitive hashing; BLAKE3 also supports keyed and tree modes |
| SHA-1 | Deprecated | Legacy compatibility only — collisions are practical |
| MD5 | Broken | Nothing security-relevant; kept for checksums and legacy ids |
| CRC32 | Not cryptographic | Detecting accidental corruption — not tampering |
Two distinctions are worth keeping straight. A checksum like CRC32 detects random corruption, and an attacker can trivially produce a different input with the same checksum — it is not a security control. A collision is two different inputs with the same digest; for MD5 and SHA-1, collisions have been constructed, which is why neither is safe for signatures. For file-integrity work, SHA-256 is the default and has been for years.
HMAC: a hash bound to a key
A plain hash proves that a value has not changed since it was hashed; it does not prove who hashed it, because anyone can compute a hash. HMAC fixes that by mixing a secret key into the computation, so only someone holding the key can produce a valid tag. That is what makes it useful for webhook signatures and API request signing.
tag = HMAC-SHA256(secret, message)
Two implementation notes. First, compare tags in constant time — a byte-by-byte comparison that exits early leaks how much of the tag matched, which is enough to forge one over many attempts. Second, the secret must be long and random; HMAC's security is bounded by the key's entropy, and a short key makes the construction guessable no matter how strong the hash is.
Where the three get confused in practice
- API keys stored as hashes. This is correct — store a hash, compare on lookup — but the key must be high-entropy, or it is guessable from the hash. Unlike passwords, an API key is machine-generated, so make it long and random and a fast hash is fine.
- “Signed” URLs. A URL with an HMAC over its parameters is a signature, not encryption. The parameters are visible; only their integrity is protected.
- Checksums for downloads. Publishing a SHA-256 alongside a file is useful only if the checksum is delivered over a channel the attacker does not control. If both come from the same compromised server, the checksum proves nothing.
- Hashing to “anonymise”. Hashing an email address does not anonymise it — the space of possible emails is small enough to enumerate, and the same address always produces the same hash, so it is a stable identifier.
A note on password cost
The iteration count is the thing that makes password hashing work, and it needs to be chosen for the hardware an attacker would use, not for the hardware of five years ago. Current guidance puts Argon2id at tens of megabytes of memory and a tuned iteration count, and bcrypt at a cost factor that takes roughly a tenth of a second on your server. Measure it on the machine that will run it; a cost that makes login feel slow is too high, and one that finishes in a millisecond is too low.