What a hash is
A cryptographic hash function maps input of any length to a fixed-size digest. The same input always gives the same digest, a one-bit change in the input changes the digest completely, and it is infeasible to find an input for a given digest or two inputs with the same digest. Hashes are used to verify downloads, deduplicate content, fingerprint files, and derive identifiers.
Text is hashed as its UTF-8 bytes, without a trailing newline. That is why echo abc | sha256sum gives a different result from hashing abc here: echo appends \n. Use printf '%s' abc | sha256sum to compare.
Which algorithm
| Algorithm | Digest | Status | Use it for |
|---|---|---|---|
| SHA-256 | 256 bits | Recommended | Integrity checks, content addressing, signatures, HMAC. The default when in doubt. |
| SHA-512 | 512 bits | Recommended | Same family; often faster than SHA-256 on 64-bit CPUs. |
| SHA-384 | 384 bits | Recommended | Truncated SHA-512. Common in TLS cipher suites and JWT ES384. |
| SHA-1 | 160 bits | Deprecated | Collisions are practical (SHAttered, 2017). Only for legacy compatibility such as Git object IDs. |
| MD5 | 128 bits | Broken | Collisions are trivial. Acceptable only as a non-security checksum where the other side requires it. |
Hashing is not password storage
A plain SHA-256 of a password is not safe to store. Fast hashes are designed to be fast, which is precisely what lets an attacker test billions of guesses per second against a leaked database. Passwords need a password hashing function that is deliberately slow and memory-hard, with a per-user salt: Argon2id, scrypt or bcrypt. Every mainstream framework provides one; use it rather than composing your own from SHA.
Hashing is also not encryption. A hash cannot be reversed to recover the input, and there is no key. If you need to get the data back, you need encryption, not a hash.
HMAC
An HMAC (RFC 2104) combines a hash with a secret key to produce a message authentication code. It proves that whoever produced the tag knew the key and that the message was not altered. Webhook signatures (GitHub, Stripe, Slack) and HS256 JWTs are HMAC-SHA256. Enter a key above and every row becomes the corresponding HMAC; the key is used as UTF-8 bytes.
In code
Command line
sha256sum file.iso
shasum -a 256 file.iso # macOS
printf '%s' 'abc' | sha256sum
printf '%s' 'message' | openssl dgst -sha256 -hmac 'key'
JavaScript (Web Crypto)
const data = new TextEncoder().encode("abc");
const buf = await crypto.subtle.digest("SHA-256", data);
const hex = [...new Uint8Array(buf)].map(b => b.toString(16).padStart(2, "0")).join("");
// ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
Python
import hashlib, hmac
hashlib.sha256(b"abc").hexdigest()
hmac.new(b"key", b"message", hashlib.sha256).hexdigest()
Notes on this implementation
SHA-1, SHA-256, SHA-384, SHA-512 and their HMACs use the browser's Web Crypto API. MD5 is not available in Web Crypto, so it is implemented in JavaScript from RFC 1321; HMAC-MD5 follows RFC 2104 on top of it. Files are read locally with the File API and hashed in memory, so very large files are limited by available memory. Nothing is uploaded.