Hashing Fundamentals
One-way functions for integrity verification, content addressing, and commitment schemes
-- SHA-256 for interoperability, BLAKE3 for performance, and never MD5 or SHA-1 for
security
When to Use
- Verifying file or data integrity (checksums, download verification, package signing)
- Content addressing (deduplication, cache keys, Git object IDs, container image digests)
- Generating deterministic identifiers from variable-length input
- Choosing a hash function for a new system or migrating away from a deprecated one
- Reviewing code that uses hashing and assessing whether the right function and use
pattern is applied
- Understanding why MD5 or SHA-1 must be replaced in security-sensitive contexts
Threat Context
Weak hash functions enable collision attacks (finding two different inputs that produce
the same hash), preimage attacks (finding an input that produces a specific target hash),
and second preimage attacks (finding a different input with the same hash as a known
input). MD5 collisions can be generated in seconds on commodity hardware -- Wang et al.
demonstrated the first practical MD5 collision in 2004, and by 2012, the Flame malware
exploited an MD5 chosen-prefix collision to forge a Microsoft code-signing certificate,
enabling nation-state malware to masquerade as a legitimate Windows update. SHA-1
collisions were demonstrated practically by Google and CWI Amsterdam in 2017 (the
SHAttered attack), producing two distinct PDF files with identical SHA-1 hashes at a cost
of approximately $110,000 in cloud computing. These attacks enable forged digital
certificates, tampered software distribution packages, Git repository poisoning, and
bypassed integrity checks in any system relying on the compromised hash function.
Instructions
For general-purpose cryptographic hashing, use SHA-256. SHA-256 (part of the SHA-2
family, designed by the NSA, standardized by NIST in 2001) produces a 256-bit digest
and provides 128-bit collision resistance and 256-bit preimage resistance. It is
universally supported across every programming language, operating system, and
cryptographic library. SHA-256 is the standard choice for integrity verification,
digital signature hashing, certificate fingerprints, blockchain proof-of-work, and any
context requiring a well-analyzed, interoperable cryptographic hash. SHA-512 offers the
same security margin with better performance on 64-bit platforms due to its use of
64-bit arithmetic operations.
For performance-sensitive hashing, use BLAKE3. BLAKE3 is a cryptographic hash
function released in 2020, derived from the BLAKE2/ChaCha cipher family. It is 6-14x
faster than SHA-256 on modern CPUs by exploiting SIMD parallelism (AVX-512, NEON) and
internal tree hashing that parallelizes across multiple cores. BLAKE3 provides 128-bit
security against all known attacks. Use BLAKE3 for content addressing, file
deduplication, Merkle tree construction, and any use case where hash throughput is a
bottleneck. BLAKE3 is not yet NIST-standardized, so use SHA-256 when FIPS 140-2/140-3
compliance is required. BLAKE2b (BLAKE3's predecessor) is standardized in RFC 7693 and
is a suitable intermediate choice.
For defense-in-depth against structural attacks, consider SHA-3 (Keccak). SHA-3
uses the sponge construction, which is fundamentally different from the Merkle-Damgard
construction used by SHA-2, MD5, and SHA-1. If a structural breakthrough ever
compromises the Merkle-Damgard design (affecting the entire SHA-2 family
simultaneously), SHA-3 would be unaffected. SHA-3-256 provides 128-bit collision
resistance, identical to SHA-256. In practice, SHA-256 is not under credible threat,
but defense-critical or long-lived systems (government archives, root certificate
authorities) may use SHA-3-256 as a hedge. SHA-3 also natively supports
variable-length output via SHAKE128 and SHAKE256 (extendable output functions), which
is useful for key derivation and domain separation.
Never use MD5 or SHA-1 for security purposes. MD5 is completely broken for
collision resistance -- chosen-prefix collisions (where the attacker controls prefixes
of both inputs) can be computed in hours on a single machine. SHA-1 is similarly
broken: the SHAttered attack demonstrated a practical collision, and further research
(Leurent and Peyrin, 2020) reduced chosen-prefix collision cost to approximately
$45,000. Both MD5 and SHA-1 are acceptable only for non-security checksums where
adversarial tampering is not in the threat model (e.g., verifying data integrity over a
reliable channel, deduplication in trusted storage). When encountering MD5 or SHA-1 in
existing code, assess whether the context is security-sensitive; if so, migration to
SHA-256 is urgent.
Understand the three security properties of cryptographic hash functions:
- Preimage resistance (one-wayness): Given a hash output H, it is computationally
infeasible to find any input m such that hash(m) = H. A hash function with n-bit
output provides up to n-bit preimage resistance. This property ensures that hashes
cannot be "reversed" to recover the original input.
- Second preimage resistance: Given a specific input m1, it is computationally
infeasible to find a different input m2 such that hash(m1) = hash(m2). This property
ensures that an attacker cannot find a substitute input that matches a known hash,
which would enable undetected document or data substitution.
- Collision resistance: It is computationally infeasible to find any two distinct
inputs m1 and m2 such that hash(m1) = hash(m2). Due to the birthday paradox,
collision resistance is at most n/2 bits for an n-bit hash (2^128 operations for
SHA-256). Collision resistance is the strongest property and implies second preimage
resistance.
Hashing is NOT encryption. Hashing is a one-way function: given input m, you can
compute hash(m), but given hash(m), you cannot recover m. Encryption is a two-way
function: given plaintext and a key, you can encrypt; given ciphertext and the key, you
can decrypt. Never hash data you need to recover (use encryption). Never encrypt data
you only need to verify (use hashing). This distinction is fundamental: hashing
provides integrity and commitment; encryption provides confidentiality.
Hashing is NOT a MAC. A bare hash -- SHA-256(message) -- does not authenticate
the sender. Anyone who knows the message can compute its hash. A Message
Authentication Code (MAC) combines the hash with a secret key, so only parties
possessing the key can compute or verify the MAC. Use HMAC (HMAC-SHA256, HMAC-SHA384)
when you need to verify both integrity and authenticity. Naive constructions like
hash(key || message) are vulnerable to length extension attacks on Merkle-Damgard
hashes. See the security-hmac-signatures skill.
Details
Length Extension Attacks
SHA-256, SHA-512, and all Merkle-Damgard hash functions are vulnerable to length
extension: given hash(m) and the length of m (but not m itself), an attacker can compute
hash(m || padding || attacker_suffix) for any chosen suffix, without knowing m. This is
possible because the final internal state of a Merkle-Damgard hash is the hash output,
and that state can be used to initialize a new hash computation that "continues" from
where the original left off.
This breaks naive keyed-hash authentication schemes like hash(secret || message): an
attacker who observes the hash and knows the message length can append arbitrary data and
compute a valid hash. Real-world exploits include API signature bypasses where servers
used hash(api_key || request_params) for authentication.
Mitigations:
- HMAC nests the hash in a specific construction -- hash(K XOR opad || hash(K XOR
ipad || message)) -- that is provably secure against length extension.
- SHA-3 (Keccak) uses the sponge construction, which absorbs input and squeezes
output through a capacity parameter. The internal state is larger than the output,
making length extension infeasible.
- BLAKE3 uses a tree/chaining construction that is also immune to length extension.
Birthday Paradox and Collision Probability
The birthday paradox states that in a set of n randomly chosen values from a space of
size N, the probability of at least one collision exceeds 50% when n approaches sqrt(N).
For hash functions:
- SHA-256 (256-bit output): collision expected after ~2^128 hashes --
computationally infeasible with current or foreseeable technology.
- SHA-1 (160-bit output): collision expected after ~2^80 hashes -- within reach of
well-funded attackers, as SHAttered demonstrated.
- MD5 (128-bit output): collision expected after ~2^64 hashes -- trivially achievable
on modern hardware.
This is why hash output length matters for security: a 128-bit hash provides only 64-bit
collision resistance, which is insufficient for any security application.
Content Addressing Pattern
Content addressing uses the hash of data as its identifier/address, making integrity
self-verifying:
- Git uses SHA-1 for object IDs (commits, trees, blobs), migrating to SHA-256 to
address collision concerns.
- IPFS uses multihash (a self-describing format: hash function identifier + digest
length + digest), allowing algorithm agility.
- Docker/OCI uses SHA-256 for layer digests and image manifests.
- Content Delivery Networks use content hashes for cache keys, enabling global
deduplication.
The pattern: store(hash(content), content) and retrieve(hash) -> content. On
retrieval, recompute the hash and verify it matches the address. If the content has been
tampered with, the hash will not match and the tampering is detected. This provides
integrity without requiring a separate signature or MAC, as long as the hash-to-content
binding was established through a trusted channel.
Hash Function Selection Decision Tree
- Need FIPS 140-2/140-3 compliance? Use SHA-256 or SHA-3-256.
- Need maximum throughput and no FIPS requirement? Use BLAKE3.
- Need defense-in-depth against Merkle-Damgard structural attacks? Use SHA-3-256.
- Non-security checksum (error detection, not adversarial)? Use CRC32 or xxHash
(not cryptographic, but extremely fast).
- Password storage? Not a general-purpose hash -- use Argon2id, bcrypt, or scrypt
(see
security-credential-storage).
- HMAC / keyed authentication? Use HMAC-SHA256 (see
security-hmac-signatures).
Anti-Patterns
MD5 for integrity in adversarial contexts. MD5 chosen-prefix collisions enable an
attacker to create two files with identical hashes but different content. The Flame
malware (2012) used an MD5 collision to forge a Microsoft code-signing certificate,
allowing malware to be distributed through Windows Update. MD5 is acceptable only for
non-security checksums where no adversary is in the threat model.
SHA-256(password) for credential storage. General-purpose hash functions are
designed to be fast -- a modern GPU can compute billions of SHA-256 hashes per second.
This speed advantage benefits attackers performing brute-force or dictionary attacks
against password hashes. Purpose-built password hashing functions (Argon2id, bcrypt,
scrypt) are deliberately slow, memory-hard, and parameterizable to maintain resistance
as hardware improves. See security-credential-storage.
hash(secret || message) for authentication. Vulnerable to length extension attacks
on all Merkle-Damgard hashes (SHA-256, SHA-512, MD5, SHA-1). An attacker who observes
the hash output and knows the message can append arbitrary data and compute a valid
hash without knowing the secret. Use HMAC(key, message) instead. HMAC is provably
secure under standard assumptions and is immune to length extension regardless of the
underlying hash function.
Truncating hashes without understanding the security impact. Truncating SHA-256
output from 256 bits to 128 bits reduces collision resistance from 2^128 to 2^64 -- a
reduction of 2^64 in the attacker's required work. If space constraints require shorter
hashes, explicitly analyze whether the reduced collision resistance is acceptable for
the specific threat model and document the decision. For content addressing where
collision probability (not adversarial collision) is the concern, truncation may be
acceptable with sufficient analysis.
Assuming hash uniqueness as an invariant. Hash functions map an infinite input
space to a finite output space -- collisions exist by the pigeonhole principle. Systems
that assume hash uniqueness without verification will fail silently when collisions
occur (whether natural or adversarial). Content-addressed storage must verify that
retrieved content matches the expected content, not just the hash. Database schemas
using hash columns as unique keys must handle collision cases.
1---2name: security-hashing-fundamentals3description: Hashing Fundamentals4---5# Hashing Fundamentals67> One-way functions for integrity verification, content addressing, and commitment schemes8> -- SHA-256 for interoperability, BLAKE3 for performance, and never MD5 or SHA-1 for9> security1011## When to Use1213- Verifying file or data integrity (checksums, download verification, package signing)14- Content addressing (deduplication, cache keys, Git object IDs, container image digests)15- Generating deterministic identifiers from variable-length input16- Choosing a hash function for a new system or migrating away from a deprecated one17- Reviewing code that uses hashing and assessing whether the right function and use18 pattern is applied19- Understanding why MD5 or SHA-1 must be replaced in security-sensitive contexts2021## Threat Context2223Weak hash functions enable collision attacks (finding two different inputs that produce24the same hash), preimage attacks (finding an input that produces a specific target hash),25and second preimage attacks (finding a different input with the same hash as a known26input). MD5 collisions can be generated in seconds on commodity hardware -- Wang et al.27demonstrated the first practical MD5 collision in 2004, and by 2012, the Flame malware28exploited an MD5 chosen-prefix collision to forge a Microsoft code-signing certificate,29enabling nation-state malware to masquerade as a legitimate Windows update. SHA-130collisions were demonstrated practically by Google and CWI Amsterdam in 2017 (the31SHAttered attack), producing two distinct PDF files with identical SHA-1 hashes at a cost32of approximately $110,000 in cloud computing. These attacks enable forged digital33certificates, tampered software distribution packages, Git repository poisoning, and34bypassed integrity checks in any system relying on the compromised hash function.3536## Instructions37381. **For general-purpose cryptographic hashing, use SHA-256.** SHA-256 (part of the SHA-239 family, designed by the NSA, standardized by NIST in 2001) produces a 256-bit digest40 and provides 128-bit collision resistance and 256-bit preimage resistance. It is41 universally supported across every programming language, operating system, and42 cryptographic library. SHA-256 is the standard choice for integrity verification,43 digital signature hashing, certificate fingerprints, blockchain proof-of-work, and any44 context requiring a well-analyzed, interoperable cryptographic hash. SHA-512 offers the45 same security margin with better performance on 64-bit platforms due to its use of46 64-bit arithmetic operations.47482. **For performance-sensitive hashing, use BLAKE3.** BLAKE3 is a cryptographic hash49 function released in 2020, derived from the BLAKE2/ChaCha cipher family. It is 6-14x50 faster than SHA-256 on modern CPUs by exploiting SIMD parallelism (AVX-512, NEON) and51 internal tree hashing that parallelizes across multiple cores. BLAKE3 provides 128-bit52 security against all known attacks. Use BLAKE3 for content addressing, file53 deduplication, Merkle tree construction, and any use case where hash throughput is a54 bottleneck. BLAKE3 is not yet NIST-standardized, so use SHA-256 when FIPS 140-2/140-355 compliance is required. BLAKE2b (BLAKE3's predecessor) is standardized in RFC 7693 and56 is a suitable intermediate choice.57583. **For defense-in-depth against structural attacks, consider SHA-3 (Keccak).** SHA-359 uses the sponge construction, which is fundamentally different from the Merkle-Damgard60 construction used by SHA-2, MD5, and SHA-1. If a structural breakthrough ever61 compromises the Merkle-Damgard design (affecting the entire SHA-2 family62 simultaneously), SHA-3 would be unaffected. SHA-3-256 provides 128-bit collision63 resistance, identical to SHA-256. In practice, SHA-256 is not under credible threat,64 but defense-critical or long-lived systems (government archives, root certificate65 authorities) may use SHA-3-256 as a hedge. SHA-3 also natively supports66 variable-length output via SHAKE128 and SHAKE256 (extendable output functions), which67 is useful for key derivation and domain separation.68694. **Never use MD5 or SHA-1 for security purposes.** MD5 is completely broken for70 collision resistance -- chosen-prefix collisions (where the attacker controls prefixes71 of both inputs) can be computed in hours on a single machine. SHA-1 is similarly72 broken: the SHAttered attack demonstrated a practical collision, and further research73 (Leurent and Peyrin, 2020) reduced chosen-prefix collision cost to approximately74 $45,000. Both MD5 and SHA-1 are acceptable only for non-security checksums where75 adversarial tampering is not in the threat model (e.g., verifying data integrity over a76 reliable channel, deduplication in trusted storage). When encountering MD5 or SHA-1 in77 existing code, assess whether the context is security-sensitive; if so, migration to78 SHA-256 is urgent.79805. **Understand the three security properties of cryptographic hash functions:**81 - **Preimage resistance (one-wayness):** Given a hash output H, it is computationally82 infeasible to find any input m such that hash(m) = H. A hash function with n-bit83 output provides up to n-bit preimage resistance. This property ensures that hashes84 cannot be "reversed" to recover the original input.85 - **Second preimage resistance:** Given a specific input m1, it is computationally86 infeasible to find a different input m2 such that hash(m1) = hash(m2). This property87 ensures that an attacker cannot find a substitute input that matches a known hash,88 which would enable undetected document or data substitution.89 - **Collision resistance:** It is computationally infeasible to find any two distinct90 inputs m1 and m2 such that hash(m1) = hash(m2). Due to the birthday paradox,91 collision resistance is at most n/2 bits for an n-bit hash (2^128 operations for92 SHA-256). Collision resistance is the strongest property and implies second preimage93 resistance.94956. **Hashing is NOT encryption.** Hashing is a one-way function: given input m, you can96 compute hash(m), but given hash(m), you cannot recover m. Encryption is a two-way97 function: given plaintext and a key, you can encrypt; given ciphertext and the key, you98 can decrypt. Never hash data you need to recover (use encryption). Never encrypt data99 you only need to verify (use hashing). This distinction is fundamental: hashing100 provides integrity and commitment; encryption provides confidentiality.1011027. **Hashing is NOT a MAC.** A bare hash -- SHA-256(message) -- does not authenticate103 the sender. Anyone who knows the message can compute its hash. A Message104 Authentication Code (MAC) combines the hash with a secret key, so only parties105 possessing the key can compute or verify the MAC. Use HMAC (HMAC-SHA256, HMAC-SHA384)106 when you need to verify both integrity and authenticity. Naive constructions like107 hash(key || message) are vulnerable to length extension attacks on Merkle-Damgard108 hashes. See the `security-hmac-signatures` skill.109110## Details111112### Length Extension Attacks113114SHA-256, SHA-512, and all Merkle-Damgard hash functions are vulnerable to length115extension: given hash(m) and the length of m (but not m itself), an attacker can compute116hash(m || padding || attacker_suffix) for any chosen suffix, without knowing m. This is117possible because the final internal state of a Merkle-Damgard hash is the hash output,118and that state can be used to initialize a new hash computation that "continues" from119where the original left off.120121This breaks naive keyed-hash authentication schemes like hash(secret || message): an122attacker who observes the hash and knows the message length can append arbitrary data and123compute a valid hash. Real-world exploits include API signature bypasses where servers124used hash(api_key || request_params) for authentication.125126Mitigations:127128- **HMAC** nests the hash in a specific construction -- hash(K XOR opad || hash(K XOR129 ipad || message)) -- that is provably secure against length extension.130- **SHA-3 (Keccak)** uses the sponge construction, which absorbs input and squeezes131 output through a capacity parameter. The internal state is larger than the output,132 making length extension infeasible.133- **BLAKE3** uses a tree/chaining construction that is also immune to length extension.134135### Birthday Paradox and Collision Probability136137The birthday paradox states that in a set of n randomly chosen values from a space of138size N, the probability of at least one collision exceeds 50% when n approaches sqrt(N).139For hash functions:140141- **SHA-256** (256-bit output): collision expected after ~2^128 hashes --142 computationally infeasible with current or foreseeable technology.143- **SHA-1** (160-bit output): collision expected after ~2^80 hashes -- within reach of144 well-funded attackers, as SHAttered demonstrated.145- **MD5** (128-bit output): collision expected after ~2^64 hashes -- trivially achievable146 on modern hardware.147148This is why hash output length matters for security: a 128-bit hash provides only 64-bit149collision resistance, which is insufficient for any security application.150151### Content Addressing Pattern152153Content addressing uses the hash of data as its identifier/address, making integrity154self-verifying:155156- **Git** uses SHA-1 for object IDs (commits, trees, blobs), migrating to SHA-256 to157 address collision concerns.158- **IPFS** uses multihash (a self-describing format: hash function identifier + digest159 length + digest), allowing algorithm agility.160- **Docker/OCI** uses SHA-256 for layer digests and image manifests.161- **Content Delivery Networks** use content hashes for cache keys, enabling global162 deduplication.163164The pattern: `store(hash(content), content)` and `retrieve(hash) -> content`. On165retrieval, recompute the hash and verify it matches the address. If the content has been166tampered with, the hash will not match and the tampering is detected. This provides167integrity without requiring a separate signature or MAC, as long as the hash-to-content168binding was established through a trusted channel.169170### Hash Function Selection Decision Tree171172- Need FIPS 140-2/140-3 compliance? Use **SHA-256** or **SHA-3-256**.173- Need maximum throughput and no FIPS requirement? Use **BLAKE3**.174- Need defense-in-depth against Merkle-Damgard structural attacks? Use **SHA-3-256**.175- Non-security checksum (error detection, not adversarial)? Use **CRC32** or **xxHash**176 (not cryptographic, but extremely fast).177- Password storage? **Not a general-purpose hash** -- use Argon2id, bcrypt, or scrypt178 (see `security-credential-storage`).179- HMAC / keyed authentication? Use **HMAC-SHA256** (see `security-hmac-signatures`).180181## Anti-Patterns1821831. **MD5 for integrity in adversarial contexts.** MD5 chosen-prefix collisions enable an184 attacker to create two files with identical hashes but different content. The Flame185 malware (2012) used an MD5 collision to forge a Microsoft code-signing certificate,186 allowing malware to be distributed through Windows Update. MD5 is acceptable only for187 non-security checksums where no adversary is in the threat model.1881892. **SHA-256(password) for credential storage.** General-purpose hash functions are190 designed to be fast -- a modern GPU can compute billions of SHA-256 hashes per second.191 This speed advantage benefits attackers performing brute-force or dictionary attacks192 against password hashes. Purpose-built password hashing functions (Argon2id, bcrypt,193 scrypt) are deliberately slow, memory-hard, and parameterizable to maintain resistance194 as hardware improves. See `security-credential-storage`.1951963. **hash(secret || message) for authentication.** Vulnerable to length extension attacks197 on all Merkle-Damgard hashes (SHA-256, SHA-512, MD5, SHA-1). An attacker who observes198 the hash output and knows the message can append arbitrary data and compute a valid199 hash without knowing the secret. Use HMAC(key, message) instead. HMAC is provably200 secure under standard assumptions and is immune to length extension regardless of the201 underlying hash function.2022034. **Truncating hashes without understanding the security impact.** Truncating SHA-256204 output from 256 bits to 128 bits reduces collision resistance from 2^128 to 2^64 -- a205 reduction of 2^64 in the attacker's required work. If space constraints require shorter206 hashes, explicitly analyze whether the reduced collision resistance is acceptable for207 the specific threat model and document the decision. For content addressing where208 collision probability (not adversarial collision) is the concern, truncation may be209 acceptable with sufficient analysis.2102115. **Assuming hash uniqueness as an invariant.** Hash functions map an infinite input212 space to a finite output space -- collisions exist by the pigeonhole principle. Systems213 that assume hash uniqueness without verification will fail silently when collisions214 occur (whether natural or adversarial). Content-addressed storage must verify that215 retrieved content matches the expected content, not just the hash. Database schemas216 using hash columns as unique keys must handle collision cases.