Hashing & Integrity
Overview
Fingerprinting data: hash functions, MACs, and storing passwords.
Hashing is how cryptography answers the question “is this the same data, and has anyone changed it?”. A cryptographic hash turns any input into a short, fixed-size fingerprint that is practically impossible to forge or reverse. That single idea underpins integrity checks, digital signatures, content-addressed storage, message authentication, and password storage, and each of those uses has its own pitfalls. This group breaks them apart.
The properties that make a hash cryptographic
Any function that maps arbitrary data to a fixed size is a hash. What makes one cryptographic is a set of hardness guarantees that ordinary checksums (like CRC32) do not provide:
| Property | Meaning | Why it matters |
|---|---|---|
| Preimage resistance | Given a hash, you cannot find an input that produces it | Protects one-way commitments |
| Second-preimage resistance | Given one input, you cannot find a different input with the same hash | Stops targeted substitution |
| Collision resistance | You cannot find any two inputs with the same hash | Underpins signatures and dedupe |
| Avalanche effect | One flipped input bit changes about half the output bits | No structure leaks through |
A CRC will happily collide on purpose and is trivial to reverse, so it detects accidental corruption but never a deliberate attacker. Cryptographic hashes (SHA-256, SHA-3) are built to resist an adversary who is actively trying to cheat. The Hash Functions page goes deep on these properties and on which algorithms still hold them.
Try a hash and watch the avalanche effect:
mkdir -p ~/crypto-lab && cd ~/crypto-lab
printf 'the quick brown fox' | openssl dgst -sha256
printf 'the quick brown fox.' | openssl dgst -sha256
Expected output:
SHA2-256(stdin)= 05c6bbda2f5b8 decafe... (64 hex chars)
SHA2-256(stdin)= 9e1a7c33b0f21 differsentirely... (64 hex chars)
Adding a single period changes essentially every output bit. That is the avalanche effect, and it is what lets a hash act as a reliable fingerprint.
Proving a message is untampered and from the right sender
A plain hash detects accidental corruption, but it does not prove who sent something: an attacker who alters a message can simply recompute the hash. To bind a message to a secret, you need a Message Authentication Code (MAC). HMAC combines a hash with a shared secret key so that only holders of the key can produce or verify the tag. If two parties share a key, a valid HMAC proves the message is unchanged and came from someone with the key.
When the parties do not share a secret (for example, verifying software from a vendor), you use a digital signature instead, which relies on public-key cryptography. The trade-off between shared-key MACs and public-key signatures is covered in HMAC & MACs.
cd ~/crypto-lab
KEY=$(openssl rand -hex 32)
printf 'transfer approved' | openssl dgst -sha256 -mac HMAC -macopt hexkey:$KEY
Expected output:
HMAC-SHA2-256(stdin)= 7b1e0a...c4 (64 hex chars, depends on the random key)
Why password storage is its own problem
It is tempting to reuse a fast hash like SHA-256 to store passwords, but that is a serious mistake. Fast hashes are fast for the attacker too: a leaked database of SHA-256 password hashes can be cracked at billions of guesses per second on a GPU. Password storage needs the opposite of speed. It needs functions that are deliberately slow and memory-hard, with a unique salt per password, so that guessing is expensive for the attacker while a single legitimate check stays cheap enough. That is the job of bcrypt, scrypt, and Argon2, covered in Password Hashing.
The three sub-pages map to three distinct problems, and mixing them up is a classic source of vulnerabilities:
- Integrity and fingerprinting: plain cryptographic hashes (
Hash Functions). - Authenticity with a shared key: MACs and HMAC (
HMAC & MACs). - Storing secrets that humans choose: slow password hashes (
Password Hashing).
Practical Guidance
- Use SHA-256, SHA-512, or SHA-3 for integrity and fingerprinting. Never use MD5 or SHA-1 for security purposes (see
Hash Functions). - Never use a bare hash for authenticity. To prove a message came from a key holder, use HMAC, not
hash(message). - Never store passwords with a plain fast hash. Use Argon2id, scrypt, or bcrypt with a per-password salt and a tuned work factor.
- Do not confuse a checksum (CRC) with a cryptographic hash. Only the latter resists a deliberate attacker.
- Verify hashes and MACs with constant-time comparison to avoid timing side channels. Libraries expose this; use it.
- Match the tool to the problem: fingerprints, authenticity, and password storage are three different jobs with three different primitives.