Hash, encrypt, encode: three words that are not the same

“Can you decrypt this hash?” is a question with no answer, because it assumes three different operations are the same one. They are not, and choosing the wrong one is a security bug rather than a preference.

The one-line distinction

OperationReversible?Needs a key?Purpose
EncodeYes, triviallyNoMake data fit a channel (Base64, percent-encoding)
HashNo, by designNoProve content is unchanged; store a verifier instead of a secret
EncryptYes, with the keyYesKeep 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:

UseRight toolWhy
File integrity, checksums, content addressingSHA-256 / SHA-512Fast is a feature
Password storageArgon2id, scrypt, bcrypt, PBKDF2Slow by design, salted, tunable cost
Message authentication (is this really from them?)HMAC-SHA-256A hash bound to a secret key
Signatures with public verificationEd25519, ECDSA, RSA-PSSVerify 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…UseDo not use
Check a download is intactSHA-256Base64, MD5
Store user passwordsArgon2id / bcryptSHA-256, MD5, encryption
Send data through a JSON APIBase64Encryption (unless it must be secret)
Keep a note private on your own deviceAES-256-GCM with a strong passphraseHashing (you cannot read it back)
Compare two secretsConstant-time comparisonPlain ===, hashing then comparing
Sign a message so others can verifyEd25519 / ECDSA, or HMAC if both sides share a keyA 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:

AlgorithmStatusUse for
SHA-256 / SHA-512RecommendedIntegrity, checksums, content addressing, HMAC
SHA-3RecommendedWhere a sponge construction is preferred; not needed to replace SHA-2
BLAKE2 / BLAKE3RecommendedSpeed-sensitive hashing; BLAKE3 also supports keyed and tree modes
SHA-1DeprecatedLegacy compatibility only — collisions are practical
MD5BrokenNothing security-relevant; kept for checksums and legacy ids
CRC32Not cryptographicDetecting 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.

Questions this guide raises

Can I decrypt a hash?

No. A hash is a one-way function: it takes an input of any length and produces a fixed-length digest, and there is no key that reverses it. The only attack is guessing inputs and hashing them, which is why password hashing uses a deliberately slow function and a per-user salt.

Why do passwords need a salt?

A salt is a unique random value stored with each password and mixed into the hash, so the same password produces different digests for different users. It defeats precomputed tables (rainbow tables) and prevents an attacker from seeing that two accounts share a password. A salt does not make a fast hash slow enough on its own.

Is SHA-256 strong enough for password storage?

No. SHA-256 is designed to be fast, which is exactly wrong for passwords: a GPU can test billions of guesses per second. Use a memory-hard, deliberately slow function such as Argon2id, scrypt or bcrypt, with a per-user salt and a cost tuned to your hardware.