What is a Hash?
A hash is a one-way function that turns any input β a sentence, a config file, a 2GB image β into a fixed-length string of hex characters. The same input always produces the same hash (deterministic), a tiny change flips about half the output bits (the avalanche effect), and you can't reverse it: given only the hash, there is no way to recover the original data.
Why SHA-256?
MD5 and SHA-1 are legacy algorithms with known collision attacks (MD5 since 2004, SHA-1 demonstrated in 2017's SHAttered attack). SHA-2 β especially SHA-256 and SHA-512 β is the current standard, used by TLS certificates, Git commits, and blockchain systems. SHA-256 produces a 256-bit digest (64 hex characters) and has no known practical collision attack.
Common Use Cases
- File integrity: Compare the SHA-256 of a downloaded file against the publisher's checksum to confirm it wasn't corrupted or tampered with.
- API signatures: HMAC-SHA256 signs requests with a shared secret so receivers can verify authenticity and integrity.
- Deduplication: Hash content to detect duplicates without comparing full files.
- Content addressing: Git and IPFS identify objects by their SHA-1/SHA-256 hash.
π‘ Pro Tip: Hashing is Not Encryption
Encryption is reversible (with a key); hashing is one-way by design. And for storing passwords, never use plain SHA-256 β it's fast, so attackers can brute-force millions of guesses per second on GPUs. Use a deliberately slow, salted password hash like bcrypt, argon2, or scrypt instead (libraries exist for every language).
Frequently Asked Questions
Can SHA-256 be reversed or decrypted?
No. SHA-256 is a one-way function with no decryption. The only "attacks" are brute force (guessing inputs until the hash matches) or rainbow tables (precomputed lookups β defeated by salting). If someone claims to "decrypt" a SHA-256 hash, they either guessed the input or the input was a known word.
What's the difference between SHA-256 and SHA-512?
Output size (256 vs 512 bits) and internal structure. SHA-512 uses 64-bit words, which makes it faster than SHA-256 on 64-bit CPUs for large inputs β but its output is twice as long. SHA-384 is SHA-512 with a truncated output, used where 256 bits feels too short but 512 is overkill. For most applications, SHA-256 is the right default.
Is this tool safe for hashing sensitive data?
Yes. The hash is computed with crypto.subtle.digest() β the browser's built-in Web Crypto API. Your input never leaves the page: there is no network request, no upload, no server. You can even disconnect from the internet and it still works.
Why shouldn't I use MD5 or SHA-1 anymore?
Both have practical collision attacks: two different inputs that produce the same hash. MD5 collisions were demonstrated in 2004 and can be computed in seconds on a laptop; SHA-1 collisions (SHAttered, 2017) cost about $110K in cloud compute. If an attacker can produce a "matching" hash for malicious content, integrity checks fail silently. Use SHA-2 (SHA-256/384/512) for anything new.
What is HMAC-SHA256?
HMAC is a keyed hash: it mixes a secret key into the hashing process so only parties who know the key can produce or verify the digest. It's the standard way to sign API requests and webhooks β a request carrying a valid HMAC could only have been signed by someone holding the shared secret.
Two tools give me different hashes for the same input β which one is wrong?
Usually neither: the bytes differ, not the algorithm. Check these four suspects in order. 1. Trailing newline β echo "hello" appends one, so the hash won't match the string you typed; use echo -n or printf. 2. CRLF vs LF β a Windows editor writes \r\n line endings while browsers normalize pasted text to \n, so the same "formatted JSON" can legitimately hash two different ways. 3. Encoding β the same text as UTF-8 and UTF-16 is different bytes, and a BOM adds three more. 4. Output format β hex vs Base64, upper vs lower case. Quick diagnostic: compare the byte lengths of the two inputs before comparing hashes. If the lengths differ, it's whitespace or encoding β the hash function is fine.
How do I generate a SHA-256 hash in Python, Node.js, or the command line?
All three ship it in the standard library. Python: hashlib.sha256(b"hello").hexdigest(). Node.js: crypto.createHash('sha256').update('hello').digest('hex'). Shell: sha256sum file.zip on Linux, or shasum -a 256 file.zip on macOS. For files larger than a few MB, stream the bytes instead of loading the whole file into memory β the browser tool above already does this, so it stays snappy on multi-gigabyte files.
Is HMAC just hash(secret + message)?
No β and that shortcut is a real vulnerability. MD5, SHA-1 and SHA-256 all use the MerkleβDamgΓ₯rd construction, which is vulnerable to a length-extension attack: anyone who sees hash(secret || message) can compute hash(secret || message || padding || extra) without ever learning the secret, because the internal state after the first block is exactly what the published digest exposes. So an attacker can append &admin=true to a signed request and forge a valid signature. HMAC defeats this by hashing twice β H(K β opad || H(K β ipad || message)) β so the outer hash hides the inner state. Never concatenate a secret with the message; use HMAC-SHA256 and compare MACs in constant time on the server.
Could two different files produce the same SHA-256 hash?
In theory yes, in practice no. A 256-bit digest can only hold 2256 distinct values, so collisions must exist β but finding one at random takes roughly 2128 attempts (the birthday bound, about 3.4 Γ 1038 hashes), which is far beyond any feasible computation. That is why SHA-256 is safe for integrity checks and content addressing. The older algorithms are not: MD5 collisions are computed in seconds on a laptop and SHA-1's cost about $110K of cloud compute, so a matching hash from those proves nothing. Need a shorter digest? Truncate SHA-256 instead of switching to MD5 β 128 bits is the accepted floor for collision resistance.
Why do two different inputs give me the same hash?
Because the bytes you hashed were the same β usually because a composite key was built by plain string concatenation. Hashing tenant + userId makes ("acme", "42") and ("acm", "e42") both become acme42, so both produce the identical digest 7c187954β¦3c1fda and one tenant can read the other's cached entry. The hash is not broken; your encoding is ambiguous. Fix it before hashing: join the parts with a separator that cannot appear inside them (acme-42 β d3f5d66eβ¦), length-prefix every field (3:acme2:42), or hash a canonical serialization instead of a hand-built string.
Does the key order of my JSON change its hash?
Yes. The digest covers the exact bytes, and key order plus whitespace are part of those bytes: {"a": 1, "b": 2} hashes to d8497d9dβ¦, {"b": 2, "a": 1} to d5b8aed2β¦, and the compact form {"a":1,"b":2} to 43258cffβ¦ β three digests for one object. That is why a payload signature created in Node can fail to verify in Go or Python: each language serializes differently. Canonicalize first β sort keys recursively, use compact separators, and agree on number formatting (RFC 8785 / JCS does exactly this) β then hash the canonical bytes on both sides.