What a hash is, and what each one is worth
A cryptographic hash reads any amount of data and produces a fixed-length digest. The same input always gives the same digest, a one-character change gives a completely different one, and there is no way back to the input — the function is one-way by construction. MD5 is specified in RFC 1321; the SHA-2 family (SHA-1, SHA-256, SHA-384, SHA-512) in NIST FIPS 180-4.
Digest length is fixed by the algorithm, so the number of hex characters identifies it at a glance:
- MD5 — 128 bits, 32 hex characters. md5("hello") = 5d41402abc4b2a76b9719d911017c592
- SHA-1 — 160 bits, 40 hex characters
- SHA-256 — 256 bits, 64 hex characters. sha256("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
- SHA-384 — 384 bits, 96 hex characters; SHA-512 — 512 bits, 128 hex characters
All five are computed at once from the same input, which is what makes the digest you were given identifiable even when nobody wrote down which algorithm produced it.
Which algorithm to use in 2026
SHA-256 is the default answer: fast, widely implemented, and with no known practical attack. Use SHA-512 when you are on 64-bit hardware and want margin — it is often faster than SHA-256 there despite the longer output. SHA-384 is a truncated SHA-512, chosen mainly to satisfy specific compliance profiles.
MD5 and SHA-1 are marked broken here for a reason. MD5 collisions have been produced on ordinary hardware since 2004, and SHA-1 fell to the SHAttered collision in 2017 and to a chosen-prefix collision in 2020 — meaning an attacker can craft two different files with the same digest. NIST has formally deprecated SHA-1 and is retiring it entirely by the end of 2030.
They remain useful for exactly one thing: detecting accidental corruption, and matching legacy systems that publish MD5 sums. If an attacker could benefit from a collision — signatures, deduplication of untrusted uploads, content addressing — MD5 and SHA-1 are not an option.
Verifying a download
Drop the file into the File tab, paste the digest the publisher listed into "Compare with", and the matching row gets a green check. The comparison accepts hex or Base64, upper or lower case, and the "<digest> <filename>" line that sha256sum and shasum -a 256 print, so you can paste a whole line from a SHA256SUMS file without trimming it.
A matching checksum proves the bytes are the ones the publisher hashed. It does not prove the publisher is who you think, and it proves nothing at all if the digest came from the same page as the download — an attacker who replaced one would replace the other. A signed checksum file (GPG, minisign) is what closes that gap.
If nothing matches, check the digest length before suspecting the file: 32 characters is MD5, 40 is SHA-1, 64 is SHA-256. A length that matches none of them usually means part of the string was cut off in copying.
HMAC: hashing with a key
A plain hash proves integrity to anyone; HMAC (RFC 2104) proves it came from someone holding the key. Enter a key and every row becomes HMAC-<algorithm> — HMAC-SHA256 with a shared secret is what Stripe, GitHub, Slack and most webhook providers use to sign their payloads.
Two details decide whether your reproduction matches theirs. The key is bytes, not text: tick "Key is hex" when the provider gave you a hex secret, or you will be hashing the ASCII of the hex digits instead of the key. And the signed value is usually the raw request body exactly as received — re-serialised JSON, with different spacing or key order, produces a different digest.
In your own code, compare signatures with a constant-time function (crypto.timingSafeEqual, hmac.compare_digest) rather than ==. String comparison returns early on the first differing byte, which leaks enough timing information to reconstruct a signature.
Why you cannot store passwords like this
Hashing a password with SHA-256 is not password storage — it is the opposite of what you want. These functions are designed to be fast, and a consumer GPU computes billions of SHA-256 digests per second, so a leaked table of unsalted digests is cracked at the speed of the attacker’s hardware. Identical passwords also produce identical digests, exposing who shares one.
Use a deliberately slow, salted password hash instead: Argon2id (the winner of the Password Hashing Competition and OWASP’s current first choice), scrypt, or bcrypt where the ecosystem requires it. They build in a per-user salt and a work factor you raise as hardware gets faster.
The same caution applies to hashing short, guessable values for "anonymisation". The SHA-256 of a phone number or an email address is trivially reversed by hashing every candidate, so a digest of that kind is still personal data.
When the digest is not what you expected
Hashes cover bytes, so anything that changes the bytes changes the digest. The usual culprits are an invisible trailing newline (echo adds one; use printf or echo -n), CRLF line endings after a file passed through Windows or Git’s autocrlf, a UTF-8 BOM at the start, and a different text encoding entirely.
The other half of the mismatches is encoding of the output, not the input: the same digest is 64 hex characters, 44 Base64 characters, or 43 Base64URL characters without padding. sha256("hello") in Base64 is LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ= — the same bytes as the hex above, written differently. Switch the output encoding rather than re-hashing.
Limits of hashing in a browser
The SHA family here comes from Web Crypto (crypto.subtle), which browsers expose only in a secure context — HTTPS or localhost. On a plain-HTTP page those rows stay empty and only MD5, which we compute ourselves, is available.
File hashing is capped at 256 MB. crypto.subtle.digest has no incremental API, so the whole file must sit in memory at once for the SHA rows; MD5 is streamed in 4 MB chunks and would have no such limit on its own. For a disc image, sha256sum or certutil -hashfile on your own machine is the right tool.
Everything is computed in this tab: the file is read with the File API and never uploaded, and the HMAC key you type lives in memory for this session only — it is written neither to the page URL nor to browser storage, so closing the tab is enough to be rid of it.