1. Introduction: Why Hashing Even Exists
SHA (Secure Hash Algorithm) was developed by the NSA and standardized by NIST in the 1990s.1
The Historical Development of SHA and NSA Involvement
The SHA family has a complex history deeply intertwined with the U.S. National Security Agency (NSA). Here’s the full story:
The Origins (1970s-1980s):
- The NSA had been researching cryptographic hash functions since the 1970s
- They developed the original SHA-0 in 1993, but it was withdrawn shortly after. The NSA discovered a flaw and released the stronger SHA-1 in 1995, three years before a public collision attack was found by researchers Chabaud and Joux in 19982
- This shows the NSA’s rigorous internal review process - they caught the flaw themselves
The Clinton Administration and Export Controls (1990s):
- In 1996, President Clinton signed Executive Order 13026, classifying encryption as “munitions”3
- This created the Export Control Classification Number (ECCN) 5A991, restricting export of strong crypto
- SHA-1 (published in 1995) offers 80 bits of collision resistance (due to its 160-bit output). While this complied with US export controls of the era, it is debated whether the NSA intentionally limited the strength or simply followed the standard design practices of the time4
- The NSA argued that 80-bit security was sufficient for commercial use, but they knew quantum computers would eventually break it
The Dual Standards Controversy:
- The NSA used classified, stronger algorithms internally while pushing weaker versions for public/commercial use
- This “dual standards” approach created distrust in the cryptographic community
- Bruce Schneier famously called this “the NSA’s two-crypto system”5
SHA-2 Development (2000s):
- After SHA-1 was broken in 2005, NIST called for SHA-2 (SHA-256, SHA-384, SHA-512)
- The NSA submitted the winning design. Unlike the later scandal with the Dual_EC_DRBG random number generator, SHA-2 uses “nothing up my sleeve” numbers (square roots of primes) for its constants.
- No backdoors have ever been found in SHA-2, and it remains the industry standard today6
- SHA-2 was standardized in 2001 as FIPS 180-2
SHA-3 Competition (2010s):
- After the SHA-2 controversy, NIST held an open competition for SHA-3
- 64 submissions from around the world, won by Keccak (pronounced “ketchak”)
- This was the first time the NSA didn’t submit the winning design
- SHA-3 was standardized in 2015 (FIPS 202), providing a completely different construction (sponge vs Merkle-Damgård). Note that Ethereum uses the original Keccak-256 submission, which has slightly different padding than the final SHA-3 standard.
The NSA’s Role Today:
- The NSA still influences NIST standards through the Commercial Solutions for Classified (CSfC) program
- They provide input on cryptographic standards but no longer dominate the process
- The agency has shifted focus to post-quantum cryptography and quantum-resistant algorithms
Note (NSA Cryptography Timeline)
1993: SHA-0 developed (withdrawn immediately)
1995: SHA-1 published (80-bit security, exportable)
2001: SHA-2 published (full 128-bit collision resistance)
2005: SHA-1 broken by Wang et al.7
2012: SHA-3 competition begins
2015: SHA-3 (Keccak) standardized
2022: NSA recommends transitioning away from SHA-1 entirely8
Encryption hides data. Hashing destroys it - irreversibly - and gives you a short fingerprint.
You can’t “decrypt” a hash. There is no key. There is no reverse function.
Hash functions solve three real problems:
- Integrity: Did this file change in transit?
- Deduplication: Are these two giant blobs actually identical?
- Commitment: Prove you knew something in 2015 without revealing it in 2015.
Every Git commit, every Docker layer, every blockchain block, every TLS certificate fingerprint, every JWT you’ve ever sent - all live on SHA.
Live Hash Calculator
⚡ Powered by hash-wasm. Runs locally in your browser. Supports large files.
Tip (Encryption ≠ Hashing)
Encryption is reversible with a key.
Hashing is a one-way street with no key. “Practical irreversibility” is the entire point.
The Mathematical Reality: The Pigeonhole Principle
Why can’t you decrypt a hash? It’s not just about mixing; it’s about information loss.
SHA-256 produces a 256-bit output. That means there are exactly possible hashes. But the input space is effectively infinite (any file, any size).
By the Pigeonhole Principle, if you have more inputs than outputs, collisions must exist. In fact, for every single SHA-256 hash, there are an infinite number of matching inputs.
The security of a hash function isn’t that collisions don’t exist-it’s that finding them is computationally impossible.
Theorem (Pigeonhole Principle Formalized)
Theorem: If items are put into containers, with , then at least one container must contain more than one item.
For Hash Functions: Let be a hash function with output space of size . The input space is infinite. Therefore, there exist infinitely many pairs of distinct inputs that hash to the same value.
Security Implication: The goal is to make finding such pairs computationally infeasible.
The Birthday Paradox
How hard is it to find a collision? You might think you need to try inputs. Wrong. You only need tries.
Theorem (The Birthday Paradox)
In a room of just 23 people, there is a >50% chance two share a birthday.
For a hash function with possible outputs, the probability of finding a collision reaches 50% after roughly attempts.
This is why 128-bit hashes (MD5) are broken. , which is computable. SHA-256 is safe because is still astronomically large.
2. The SHA Family: SHA-0 → SHA-1 → SHA-2 → SHA-3
| Year | Name | Status | Fatal Flaw / Reason for Death |
|---|---|---|---|
| 1993 | SHA-0 | Withdrawn immediately | Theoretical collision attack found before publication |
| 1995 | SHA-1 | Dead since 2017 | 2017 Google/Shanghai collision (SHAttered), 2020 chosen-prefix |
| 2001 | SHA-2 | Still safe (2025) | SHA-224, SHA-256, SHA-384, SHA-512 - Merkle-Damgard family |
| 2015 | SHA-3 | Safe & fundamentally different | Keccak sponge construction, winner of NIST competition |
SHA-2 and SHA-3 are not upgrades of each other - they are parallel families. NIST kept both because diversity is defense.
Example (SHA-1 vs SHA-2: The Critical Difference)
SHA-1 (Broken): 160-bit output, Merkle-Damgård construction
SHA-2 (Safe): 256/384/512-bit outputs, same construction but stronger constants and more rounds
Why SHA-2 survived when SHA-1 died: SHA-2 uses 64 rounds vs SHA-1’s 80, with carefully chosen rotation constants that maximize diffusion. The birthday bound for SHA-256 is operations, which remains infeasible.
Note (Current Status)
SHA-1 → officially deprecated by everyone sane after 2017
SHA-2 → still dominant (TLS, Bitcoin, Git)
SHA-3 → slowly appearing in new protocols (Signal, Ethereum 2.0 keystretch)
3. What Makes a Hash Function Secure?
Five properties you must memorize:
| Property | Human Explanation | Real-World Break Example |
|---|---|---|
| Preimage resistance | Given , impossible to find any such that | You can’t reverse a Git commit hash |
| Second-preimage resistance | Given , impossible to find with same hash | Can’t forge a CA certificate with same hash |
| Collision resistance | Impossible to find any pair with same hash | SHAttered attack on SHA-1 |
| Avalanche effect | One flipped input bit → ~50% of output bits flip | Tiny typo = completely different digest |
| Determinism + Fixed size | Same input → always same output, length always fixed | sha256sum always 64 hex chars |
Input: "hello world"SHA-256: b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
Input: "hellp world" (one letter changed)SHA-256: cd59836a7318ed89a5328ee249c5b9ab8a273acdd52b9540eeef041ef3a38557→ 100% of hex digits changedCode: Proving the Avalanche Effect
Don’t believe it? Here is a Python script to prove that flipping 1 bit changes ~50% of the output bits.
import hashlib
def get_bits(s): return bin(int(s, 16))[2:].zfill(256)
def avalanche_demo(): msg1 = b"hello world" msg2 = b"hello worle" # only last bit flipped (d=01100100 → e=01100101)
h1 = hashlib.sha256(msg1).hexdigest() h2 = hashlib.sha256(msg2).hexdigest()
bits1 = get_bits(h1) bits2 = get_bits(h2)
diff_count = sum(a != b for a, b in zip(bits1, bits2))
print(f"Msg 1: {msg1}") print(f"Hash 1: {h1}") print(f"Msg 2: {msg2}") print(f"Hash 2: {h2}") print(f"Total bits: 256") print(f"Different bits: {diff_count}") print(f"Avalanche percentage: {diff_count / 256 * 100:.2f}%")
avalanche_demo()
# Typical Output:# Different bits: 126# Avalanche percentage: 49.22%4. Inside SHA-256: How It Actually Works
SHA-256 is a Merkle–Damgård construction. It processes messages in blocks, feeding the result of one block into the next.
The Architecture
Step-by-Step Mechanics
- Pad message so length , then append 64-bit length. This ensures the message is a perfect multiple of 512 bits.
Example (Visualizing the Padding)
How does “hello” (40 bits) become 512 bits?
01101000 01100101 01101100 01101100 01101111 (hello)
1 (Append single 1 bit)
00000...00000 (Append 423 zeros)
00000...00101000 (Append 64-bit length = 40)
Total = 512 bits.
- Split into 512-bit blocks.
- Initialize eight 32-bit constants ( to ).
- These aren’t random. They are the fractional parts of the square roots of the first 8 primes (2, 3, 5, 7, 11, 13, 17, 19).
- Why? To prove there’s no “backdoor” or hidden structure.
- The Compression Function (The Core):
- Run 64 rounds of bitwise mixing.
The Math of the Rounds
Inside the loop, SHA-256 uses six logical functions on 32-bit words. Let be XOR, be AND, be NOT. is circular right rotation by bits. is right shift by bits.
Explanation (Understanding the Boolean Functions)
Choice Function : “If x then y else z” - selects bits from y or z based on x
Majority Function : Returns the bit that appears in at least 2 of the 3 inputs
Σ Functions: Non-linear permutations that ensure diffusion across the entire 32-bit word
σ Functions: Used in message expansion to create 64 words from 16 input words
Explanation (Why these specific numbers?)
Why rotate by 2, 13, and 22? These constants were chosen to maximize diffusion (spreading bits around) and minimize linearity. Changing them even slightly weakens the algorithm significantly.
Python Implementation of the Compression Loop
This is what happens inside a single block processing step:
def right_rotate(value, amount): return ((value >> amount) | (value << (32 - amount))) & 0xFFFFFFFF
def sha256_compression(chunk, H): # 1. Prepare Message Schedule W[0..63] W = [0] * 64 # Copy first 16 words from chunk for i in range(16): W[i] = int.from_bytes(chunk[i*4:(i+1)*4], 'big')
# Expand to 64 words for i in range(16, 64): s0 = right_rotate(W[i-15], 7) ^ right_rotate(W[i-15], 18) ^ (W[i-15] >> 3) s1 = right_rotate(W[i-2], 17) ^ right_rotate(W[i-2], 19) ^ (W[i-2] >> 10) W[i] = (W[i-16] + s0 + W[i-7] + s1) & 0xFFFFFFFF
# 2. Initialize Working Variables a, b, c, d, e, f, g, h = H
# 3. Main Loop (64 rounds) for i in range(64): S1 = right_rotate(e, 6) ^ right_rotate(e, 11) ^ right_rotate(e, 25) ch = (e & f) ^ ((~e) & g) temp1 = (h + S1 + ch + K[i] + W[i]) & 0xFFFFFFFF
S0 = right_rotate(a, 2) ^ right_rotate(a, 13) ^ right_rotate(a, 22) maj = (a & b) ^ (a & c) ^ (b & c) temp2 = (S0 + maj) & 0xFFFFFFFF
h = g g = f f = e e = (d + temp1) & 0xFFFFFFFF d = c c = b b = a a = (temp1 + temp2) & 0xFFFFFFFF
# 4. Add to current hash state return [ (H[0] + a) & 0xFFFFFFFF, (H[1] + b) & 0xFFFFFFFF, # ... etc for all 8 ]5. SHA-3: Why It’s Built Completely Differently
SHA-3 (Keccak) uses a Sponge Construction. It doesn’t use the Merkle–Damgård structure at all.
- 1600-bit internal state (5×5×64 grid of bits).
- Absorb phase: XOR message chunks into the state, then run the permutation.
- Squeeze phase: Read parts of the state as output, run permutation, read more…
Why Sponge wins:
- Immune to Length Extension Attacks: The internal state is never fully exposed.
- Variable Output: Can produce infinite output stream (SHAKE128/SHAKE256).
- Simpler Math: Uses only XOR, AND, NOT, and Rotations. No addition modulo .
Example (SHA-3 vs SHA-2: Construction Comparison)
SHA-2 (Merkle-Damgård):
- Processes fixed 512-bit blocks
- Output = final compression state
- Vulnerable to length extension
SHA-3 (Sponge):
- 1600-bit internal state (5×5×64 bit matrix)
- Absorb phase: XOR message into state, permute
- Squeeze phase: Extract output, permute for more
- No length extension possible
6. Length Extension Attacks (The Bug Everyone Forgets)
This is the most dangerous subtle bug in crypto. SHA-256 (and all SHA-2/MD5) has this vulnerability.
The Flaw: If you know , you can calculate without knowing the Secret.
Why? Because the output of SHA-256 is the internal state of the hasher after processing the message. You can just load that state into your own hasher and keep going!
Theorem (Length Extension Attack Mathematics)
Theorem: For Merkle-Damgård hash functions, if where is the final internal state after processing message , then:
Where is the padding applied to , and continues hashing from the intermediate state.
Security Impact: An attacker can append data to a message without knowing the original content, as long as they know the hash.
Exploit Code Example
Imagine a web API that signs requests like this:
signature = sha256(SECRET_KEY + "user=john&role=user")
An attacker sees the signature 5d9c.... They want to become admin.
import hlextend # Tool for length extension attacks
# Attacker knows:original_msg = b"user=john&role=user"original_sig = "5d9c..." # The hash they interceptedappend_msg = b"&role=admin"
# Attacker computes new signature WITHOUT knowing the secret:sha = hlextend.new('sha256')new_sig = sha.extend(append_msg, original_msg, length_of_secret, original_sig)
# Result:# New Message: "user=john&role=user" + PADDING + "&role=admin"# New Signature: Valid hash of (Secret + New Message)The Fix:
- Use HMAC:
HMAC(key, message). It does nested hashing to prevent this.
Deep Dive: How HMAC Fixes It
HMAC isn’t just hash(key + msg). It’s a nested construction that isolates the internal state.
Where:
- is the hash function (SHA-256)
- is the key (padded/hashed to block size)
- is outer padding (
0x5c5c...) - is inner padding (
0x3636...)
Because the output of the inner hash is processed again by the outer hash (with a different key mask), the attacker cannot extend the message. The internal state of the outer hash is finalized and “sealed”.
Theorem (HMAC Security Proof)
HMAC Security: If the underlying hash function has some reasonable properties (collision resistance), then HMAC is a secure MAC even if the hash function’s internal structure is known.
Key Insight: The nested construction prevents length extension because:
- Inner hash output becomes input to outer hash
- Different key padding (opad vs ipad) ensures different contexts
- Attacker cannot predict or control the outer hash’s internal state
- Use SHA-3 or BLAKE3: They are immune by design.
- Use Double Hash:
SHA256(SHA256(x))(Bitcoin does this).
7. Where SHA Is Used in the Real World
| Use Case | Which SHA | Why it matters |
|---|---|---|
| Git commits | SHA-1 → SHA-256 | Git is transitioning to SHA-256 (experimental support added in v2.29). It uses a Merkle Tree structure where commit IDs depend on parent IDs. |
| Docker images | SHA-256 | Every layer is identified by its SHA-256 hash. Ensures reproducibility and deduplication. |
| Bitcoin blocks | Double SHA-256 | SHA256(SHA256(header)) prevents length extension attacks. Mining = finding a nonce such that the hash is below target difficulty. |
| TLS certificates | SHA-256 | Certificate fingerprints are SHA-256 hashes. Pin cert fingerprints to prevent MITM via compromised CAs. |
| Package managers | SHA-256 | npm, pip, cargo all verify package integrity using SHA-256. Prevents substitution attacks during download. |
| IPFS | SHA-256 and SHA-3 | Content-addressed storage: files are identified by their hash, not location. Enables deduplication across network. |
| JWT signatures | SHA-256 (HMAC-SHA256) | JWTs sign claims with HMAC-SHA256. Verifies token wasn’t tampered with and came from expected server. |
| Blockchain merkle trees | SHA-256 (multiple layers) | Every transaction is hashed, then pairs of hashes are hashed together, forming a tree. Root is the block identifier. |
| SSL certificate pinning | SHA-256 | Apps pin the SHA-256 hash of the certificate’s public key. Prevents replacement even if CA is compromised. |
| File integrity checks | SHA-256 | sha256sum file.iso produces a checksum. Compare with official value to verify file wasn’t corrupted in transit. |
| Deduplication storage | SHA-256 | Cloud storage (Dropbox, backups) use content-hashing to identify duplicate blocks across users. |
| Ethereum smart contracts | Keccak-256 (Original submission, distinct from FIPS 202 SHA-3) | Contract addresses, storage keys, and transaction hashes all use Keccak-256. |
Example (Bitcoin Mining Mathematics)
Target Difficulty: For Bitcoin block #800,000, the target was approximately .
Mining Success Probability: Each hash attempt has probability
Expected Attempts: hashes per block
Network Hashrate: ~600 EH/s = hashes/second
Block Time: ~10 minutes (600 seconds), so hashes per block
Code: Bitcoin Mining (Proof of Work)
This is the actual logic running on millions of ASICs right now (simplified to Python).
import hashlibimport struct
def double_sha256(header_bytes): return hashlib.sha256(hashlib.sha256(header_bytes).digest()).digest()
def mine_block(block_header_prefix, target_difficulty): nonce = 0 while True: # Construct header with current nonce (4 bytes) # <Prefix 76 bytes> + <Nonce 4 bytes> header = block_header_prefix + struct.pack("<I", nonce)
block_hash = double_sha256(header)
# Check if hash is below target (interpreted as big integer) # (In reality, Bitcoin compares little-endian, but logic holds) hash_int = int.from_bytes(block_hash, 'big')
if hash_int < target_difficulty: print(f"Found Nonce: {nonce}") print(f"Hash: {block_hash.hex()}") return nonce
nonce += 1 if nonce % 1000000 == 0: print(f"Trying nonce {nonce}...")8. How to Compute and Verify Hashes in Practice
Here’s the most common real-world use case: verifying that a file you downloaded hasn’t been corrupted or tampered with.
Example: Verifying a Debian Linux ISO
When you download debian-12.7.0-amd64-netinst.iso from a mirror, the official Debian repository provides a SHA-256 checksum on their website:
8fde79cfc6b20a696200fc5c15219cf6d721e8feb367e9e0e33a79d1cb68fa83To verify on Linux/macOS:
# Compute the hash of the downloaded filesha256sum debian-12.7.0-amd64-netinst.iso
# Expected output:# 8fde79cfc6b20a696200fc5c15219cf6d721e8feb367e9e0e33a79d1cb68fa83 debian-12.7.0-amd64-netinst.iso
# If the hash matches → file is genuine# If the hash differs → file was corrupted OR replaced by attackerTo verify on Windows (PowerShell):
(Get-FileHash -Path "debian-12.7.0-amd64-netinst.iso" -Algorithm SHA256).Hash# Compare output to official SHA-256To verify on macOS (using brew-installed gnu-coreutils):
sha256sum debian-12.7.0-amd64-netinst.iso# Or with standard macOS sha256:shasum -a 256 debian-12.7.0-amd64-netinst.isoWarning (Why Verification Matters)
Real-world attack scenario:
- Attacker intercepts your download (via compromised WiFi, ISP, or network)
- Replaces legitimate ISO with one containing malware
- You install the compromised system
- Your entire system is pwned
Why SHA-256 prevents this:
- Attacker would need to modify the ISO AND craft it so the hash matches
- This is computationally infeasible (would require operations)
- Therefore, if hash matches, file is definitely unchanged
Advanced: Verifying Large Downloads with Streaming Hash
For multi-gigabyte files, you may want to compute the hash while downloading (to verify incrementally):
import hashlib
def compute_file_hash_streamed(filepath, chunk_size=65536): """Compute SHA-256 hash of a file, reading in chunks.""" sha256_hash = hashlib.sha256()
with open(filepath, "rb") as f: # Read file in 64KB chunks for chunk in iter(lambda: f.read(chunk_size), b""): sha256_hash.update(chunk) # Could print progress here: print(f"Read {bytes_read} bytes...")
return sha256_hash.hexdigest()
# Usagefile_hash = compute_file_hash_streamed("debian-12.7.0-amd64-netinst.iso")print(f"SHA-256: {file_hash}")
# Compare with officialofficial_hash = "8fde79cfc6b20a696200fc5c15219cf6d721e8feb367e9e0e33a79d1cb68fa83"if file_hash == official_hash: print("✓ File verified as genuine")else: print("✗ File has been modified - DO NOT USE")Explanation (Why Chunked Hashing?)
- RAM efficiency: Doesn’t load entire file into memory
- Progress feedback: Can display download/verification progress
- Early detection: Can stop reading if hash already mismatches (in some protocols)
- Large files: The only practical way to hash multi-GB files on machines with limited RAM
Why This Protects You
Scenario 1: File corrupted in transit (your problem)
- Network bit flip changes
0to1somewhere in the 700MB file - Hash changes completely (avalanche effect)
- Verification catches it, you re-download
Scenario 2: Attacker replaces file
- Attacker modifies ISO to include malware
- To avoid detection, they need to craft modified ISO with same SHA-256
- Infeasible: computational effort (billions of years on all Earth’s computers combined)
- Attacker gives up, finds different target
Scenario 3: Man-in-the-middle attack
- Attacker intercepts download, replaces with trojanized version
- You verify hash, it doesn’t match
- You know not to use this file
The reason SHA-256 is so effective here is the collision resistance property: it is computationally impossible for an attacker to create two different files with the same hash.
9. Case Study: The SHAttered Attack (SHA-1 is Dead)
In 2017, Google and CWI Amsterdam announced SHAttered, the first practical collision for SHA-1.
Danger (The Attack)
They generated two different PDF files with the exact same SHA-1 hash.
- File A: A PDF showing a blue background.
- File B: A PDF showing a red background.
- Hash(A) == Hash(B)
How they did it: They used an Identical-Prefix Collision attack.
- They created a special header for the PDF files.
- They used 6,500 CPU years and 110 GPU years of computation (still 100,000x faster than brute force).
- They found a collision in the compression function that allowed them to swap the content of the PDF (blue vs red) without changing the hash.
“We have broken SHA-1 in practice. … This is the result of a long line of research starting in 2005.” - shattered.io
The Impact: This killed SHA-1 for good. Browsers stopped accepting SHA-1 certificates, and Git moved to harden its SHA-1 usage (and eventually migrate to SHA-256).
10. Why SHA Should Never Be Used for Passwords
Grover’s algorithm gives a quadratic speedup. This means a quantum computer effectively halves the bit-strength of a hash function.
Theorem (Grover's Algorithm Impact)
Grover’s Algorithm: Provides quadratic speedup for searching unstructured databases.
For Hash Functions: Finding preimages or second preimages requires operations instead of .
Collision Finding: Quantum algorithms like BHT can theoretically find collisions in operations.
Post-Quantum Security: For 128-bit collision resistance, you need 256-bit hashes. For 256-bit collision resistance, you need 512-bit hashes.
| Hash | Classical Bits | Quantum Bits | Status |
|---|---|---|---|
| SHA-256 | 128 (collision) | ~85 (collision) | Weakened (theoretically) |
| SHA-384 | 192 | 96 | Safe |
| SHA-512 | 256 | 128 | Safe |
Rule of thumb: If you are building for the post-quantum era, use SHA-384 or SHA-512. 256 bits is not enough for collision resistance against a quantum adversary.
11. Alternatives to SHA (Use These Instead)
| Algorithm | Speed | Features | Best for |
|---|---|---|---|
| BLAKE3 | Extremely Fast (GB/s) | Parallel, SIMD, Merkle Tree mode | File checksums, general hashing. Faster than SHA-1, safer than SHA-2. |
| SipHash | Fast | Short-input MAC | Hash tables (prevents HashDoS attacks). |
| Argon2id | Tunable (Slow) | Memory-hard | Passwords. |
| HMAC-SHA256 | Moderate | Keyed MAC | API authentication (JWTs). |
Example (BLAKE3: The Modern Alternative)
BLAKE3 Features:
- Parallel: Can hash multiple chunks simultaneously
- SIMD-optimized: Uses CPU vector instructions for 2-3x speedup
- Merkle Tree mode: Can verify partial file integrity
- Arbitrary output length: Like SHAKE, but faster
- Performance: ~1 GB/s on modern CPUs (vs SHA-256’s ~300 MB/s)
Why it’s better than SHA-256: Same security assumptions, but 3x faster and designed for modern hardware.
12. Final Summary: What Non-Experts Always Misunderstand
Warning (Critical Takeaways for Developers)
Don’t Make These Mistakes:
- Never use raw SHA-256 for passwords → Use Argon2id
- Never use raw SHA-2 as MAC → Use HMAC-SHA256
- Never assume SHA-256 is “quantum-safe” → For collision resistance, use SHA-384 minimum
- Never roll your own crypto → Use established constructions
Default Choices for 2025:
- General hashing: BLAKE3
- Password hashing: Argon2id
- MAC: HMAC-SHA256 or KMAC (SHA-3)
- Digital signatures: Ed25519 with SHA-512
- Hashing ≠ encryption. There is no key. You cannot “decrypt” it.
- SHA-256 is not “broken” but it’s not future-proof against quantum.
- Using raw SHA for passwords is professional negligence in 2025.
- SHA is a family, not one algorithm. SHA-1 ≠ SHA-2 ≠ SHA-3.
- Length-extension attacks exist. Never use raw SHA-2 as a MAC.
- HMAC exists for a reason. Use it.
- For new designs in 2025+: default to BLAKE3 or SHA-3.
Tip
Building something that must survive the next decade?
Ellipticc Drive uses BLAKE3 for integrity, Kyber for confidentiality, and Dilithium for signatures - hybrid crypto.
Start using future-proof storage now →