StringToolsStringTools
Back to Blog
SecurityApril 9, 2026·10 min read·StringTools Team

Hash Functions Explained: MD5, SHA-256, bcrypt, Argon2 (2026)

The Invisible Foundation of Modern Security

Every time you git commit, log into a service, download an installer, or watch a Bitcoin transaction confirm, you are relying on cryptographic hash functions. Git uses SHA-1 (migrating to SHA-256) to identify every object in your repo. TLS certificates are signed over SHA-256 digests. Your laptop's firmware boots only if its SHA-256 hash matches what the manufacturer signed. Modern password databases store Argon2 digests so that even a full database leak does not compromise user credentials.

And yet, hash functions are one of the most commonly misused primitives in software. Developers still reach for MD5 in 2026 for password storage. They forget to salt. They confuse hashing with encryption. They pick SHA-256 when they should pick bcrypt — or bcrypt when they should pick Argon2id.

This guide is a working developer's reference. We will cover the formal properties of a cryptographic hash, walk through the evolution from MD5 (1991) to BLAKE3 (2020), examine the real collision attacks that broke MD5 and SHA-1, explain why you must never use SHA-256 for passwords, and finish with runnable JavaScript code using the browser's Web Crypto API. By the end, you will be able to pick the right hash function for any job and explain why in a code review.

What Is a Cryptographic Hash Function?

A hash function is a deterministic mathematical function that maps arbitrary-length input (the "message") to fixed-length output (the "digest"). A cryptographic hash function adds specific security properties that make it suitable for security use cases.

Concrete example using SHA-256:

Input: hello SHA-256 digest: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

Input: hello! (one extra character) SHA-256 digest: ce06092fb948d9ffac7d1a376e404b26b7575bcc11ee05a4615fef4fec3a308b

The output length is always 256 bits (64 hex characters) regardless of whether you hash "hi" or a 10 GB video file. Change a single bit of input, and roughly half the output bits flip — the avalanche effect.

A hash function is not encryption. Encryption is reversible with a key; hashing is one-way and keyless. You cannot recover "hello" from its SHA-256 digest — the only way back is to guess and hash each guess until the digest matches.

The Five Properties That Define a Cryptographic Hash

1. Deterministic. The same input always produces the same output. This is what allows hashes to be used as content identifiers (Git, IPFS, deduplication systems).

2. Fixed output size. MD5 produces 128 bits, SHA-1 produces 160 bits, SHA-256 produces 256 bits, SHA-512 produces 512 bits. The size bounds the security.

3. Pre-image resistance. Given a digest h, it should be computationally infeasible to find any input m such that hash(m) = h. For an ideal n-bit hash, this requires ~2^n operations.

4. Second pre-image resistance. Given a specific input m1, it should be infeasible to find a different input m2 such that hash(m1) = hash(m2). Also ~2^n work.

5. Collision resistance. It should be infeasible to find any two inputs m1 and m2 with the same hash. Due to the birthday paradox, this requires only ~2^(n/2) operations — which is why 160-bit SHA-1 (2^80 work) is now feasible to attack, but 256-bit SHA-256 (2^128 work) is not.

Bonus property: avalanche. Flipping one input bit flips ~50% of output bits. This is what makes hashes useful as fingerprints — any tampering is visible.

Hash Algorithm Evolution (1991 to 2026)

MD5 (Ron Rivest, 1991). 128-bit output. Blazing fast. Collisions first demonstrated by Xiaoyun Wang in 2004 — two different inputs producing the same MD5. By 2008, researchers forged a rogue CA certificate using MD5 collisions. Use today: file deduplication, non-security checksums. Never for passwords, signatures, or integrity against adversaries.

SHA-1 (NSA/NIST, 1995). 160-bit output. Collisions theoretically possible from 2005. In February 2017, Google published "SHAttered" — two different PDF files with the same SHA-1 hash, costing ~110 GPU-years of compute. GitHub, Git, and TLS have all moved away. Use today: legacy compatibility only.

SHA-2 family (NIST, 2001). SHA-224, SHA-256, SHA-384, SHA-512. No practical attacks in 25 years. SHA-256 is the current workhorse: TLS 1.3, Bitcoin, signed JWTs, code signing, Git (migrating).

SHA-3 / Keccak (NIST, 2015). Completely different internal construction (sponge) from SHA-2 (Merkle-Damgard). Adopted as hedge against hypothetical SHA-2 weaknesses. Not faster than SHA-2 in software, but parallelizable and resistant to length-extension attacks.

BLAKE2 (2012) and BLAKE3 (2020). Modern, fast, secure. BLAKE3 is 6-10x faster than SHA-256 in software and is parallelizable — single-digit GB/s on commodity CPUs. Gaining adoption in content-addressed storage and integrity scanning.

xxHash, MurmurHash, CityHash. Non-cryptographic — fast but trivially collidable by an adversary. Use for hash tables, bloom filters, internal deduplication. Never for security.

Why You Must Not Use SHA-256 for Passwords

SHA-256 is cryptographically secure, but it has exactly the wrong property for password storage: it is fast. A modern GPU computes ~30 billion SHA-256 hashes per second. If your database leaks, an attacker with a single RTX 4090 can try every 8-character lowercase password in minutes.

Password hashing needs slowness. Specifically, it needs tunable slowness — a work factor that can be raised as hardware gets faster. The three functions designed for this:

bcrypt (Provos & Mazieres, 1999). Work factor from 4 to 31 (doubling per step). Production default: 12. Battle-tested for 25 years. Limited to 72-byte input.

scrypt (Percival, 2009). Memory-hard — uses large RAM, defeating GPU/ASIC attackers. Good, but superseded by Argon2 for most new work.

Argon2 (Biryukov, Dinu, Khovratovich, 2015). Winner of the Password Hashing Competition. Three variants: Argon2d (GPU-resistant), Argon2i (side-channel-resistant), Argon2id (recommended hybrid). Tunable memory, time, and parallelism. Current OWASP recommendation (2024): Argon2id with m=19 MiB, t=2, p=1.

Current recommendation by use case:

Password storage — Use: Argon2id (new), bcrypt (if Argon2 unavailable) • Never: SHA-256, MD5, plain hashes

File integrity — Use: SHA-256, BLAKE3 • Never: MD5, SHA-1

Digital signatures — Use: SHA-256, SHA-3-256 • Never: MD5, SHA-1

Message authentication — Use: HMAC-SHA-256, BLAKE3 keyed • Never: plain hash(key + message)

Salt and HMAC: The Two Most Forgotten Details

Salt. A salt is random data added to each input before hashing. Two identical passwords should never produce the same stored hash. Without salt, an attacker precomputes a rainbow table once and instantly cracks every matching password across any leaked database.

Rules for salt:

- Generated per user (never shared) - At least 16 bytes from a CSPRNG - Stored alongside the hash (not secret — its job is uniqueness, not secrecy) - Regenerated on password change

Modern password hashing libraries (bcrypt, Argon2) generate and encode salt into the output string automatically. You do not need to manage it manually — you just need to use the library correctly.

HMAC (Hash-based Message Authentication Code). Defined in RFC 2104. HMAC turns a hash function into a keyed MAC — proving both integrity and authenticity of a message. Used in TLS, JWT HS256, AWS request signing.

Never use hash(key + message) — it is vulnerable to length-extension attacks against Merkle-Damgard hashes like SHA-256. Always use HMAC, which handles the key mixing correctly.

Example in Node.js:

const crypto = require('crypto'); const hmac = crypto.createHmac('sha256', secret).update(message).digest('hex');

Real-World Use Cases

1. Git commit IDs. Every commit, tree, and blob in Git is named by the SHA-1 hash of its content (SHA-256 in newer repos). This gives you cryptographic integrity for free: change history and the hashes mismatch.

2. File integrity verification. When you download Ubuntu, the site publishes SHA-256 digests. You verify locally with shasum -a 256 ubuntu.iso.

3. Password storage. Your password never leaves the login form in plaintext after hashing. Database leak reveals only digests.

4. Digital signatures. To sign a 10 MB document, you compute SHA-256(document) and sign the 32-byte digest with your private key. Verification hashes independently and verifies the signature.

5. Blockchain. Bitcoin addresses are RIPEMD-160(SHA-256(public_key)). Blocks are chained by including the previous block's SHA-256 digest. Proof-of-work is finding a nonce so block hash has N leading zeros.

6. Deduplication and content addressing. Cloud storage (S3 ETags), IPFS content IDs, Docker layer digests — all content is addressed by hash.

7. HMAC signed cookies, webhook verification. GitHub webhook deliveries include an HMAC-SHA-256 signature computed with your shared secret, preventing forged webhook calls.

Hashing in JavaScript with the Web Crypto API

The Web Crypto API (window.crypto.subtle) is built into every modern browser (Chrome 60+, Firefox 34+, Safari 11+). It runs in native code, so it is fast and secure.

Compute SHA-256 of a string:

async function sha256(message) { const data = new TextEncoder().encode(message); const digest = await crypto.subtle.digest('SHA-256', data); return Array.from(new Uint8Array(digest)) .map(b => b.toString(16).padStart(2, '0')) .join(''); }

sha256('hello').then(console.log); // 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

Compute HMAC-SHA-256:

async function hmacSha256(key, message) { const encoder = new TextEncoder(); const cryptoKey = await crypto.subtle.importKey( 'raw', encoder.encode(key), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign'] ); const sig = await crypto.subtle.sign('HMAC', cryptoKey, encoder.encode(message)); return Array.from(new Uint8Array(sig)) .map(b => b.toString(16).padStart(2, '0')).join(''); }

For password hashing in JavaScript, use argon2-browser or bcryptjs — SubtleCrypto does not implement Argon2 or bcrypt because password hashing belongs server-side.

Common Mistakes and How to Fix Them

Mistake 1: Using MD5 or SHA-1 for anything security-related. Fix: switch to SHA-256 minimum. For new designs, consider SHA-3 or BLAKE3.

Mistake 2: Using a fast hash (SHA-256) for passwords. Fix: use Argon2id or bcrypt. Aim for a hash that takes ~250ms on your production hardware.

Mistake 3: Forgetting to salt passwords. Fix: let your password hashing library handle it (bcrypt, Argon2). Do not roll your own.

Mistake 4: Using hash(key + message) as a MAC. Fix: use HMAC. Every language has a builtin.

Mistake 5: Truncating hashes to save storage bytes. Fix: store the full digest. Truncation weakens collision resistance quadratically.

Mistake 6: Comparing hashes with == in user-facing code. Fix: use constant-time comparison (crypto.timingSafeEqual in Node, hmac.compare_digest in Python) to prevent timing attacks.

Quick Reference: Choose the Right Hash

Hash function comparison at a glance:

MD5 — Output: 128 bits • Speed: Very fast • Status: Broken (2004) • Use: Non-security checksums only

SHA-1 — Output: 160 bits • Speed: Fast • Status: Broken (2017) • Use: Legacy Git compatibility only

SHA-256 — Output: 256 bits • Speed: Fast • Status: Secure • Use: Integrity, signatures, TLS, HMAC

SHA-512 — Output: 512 bits • Speed: Fast (64-bit CPUs) • Status: Secure • Use: High-security signatures

SHA-3-256 — Output: 256 bits • Speed: Moderate • Status: Secure • Use: Hedge against SHA-2, length-ext resistance

BLAKE3 — Output: 256 bits (extendable) • Speed: Very fast, parallel • Status: Secure • Use: Content addressing, high-throughput integrity

bcrypt — Output: 192 bits • Speed: Deliberately slow • Status: Secure • Use: Password storage (legacy/new)

Argon2id — Output: configurable • Speed: Deliberately slow, memory-hard • Status: Secure • Use: Password storage (recommended)

Frequently Asked Questions

Can I reverse a hash?

No — hash functions are one-way by design. However, if the input space is small (e.g., common passwords, phone numbers, short strings), an attacker can exhaustively search by hashing every candidate and checking for a match. This is exactly why password hashing uses slow, salted functions.

Is MD5 safe for anything?

Yes, for non-adversarial use: file deduplication, cache keys, CRC-style integrity checks against accidental corruption. It is still in widespread use for these. Never use MD5 where an attacker might craft inputs — passwords, signatures, certificates.

SHA-256 vs SHA-3 — which should I use?

SHA-256 for most new work. It is faster in software, has 25 years of cryptanalysis, and is universally supported. SHA-3 is your hedge if you need resistance to length-extension or want diversity in your cryptographic stack.

What is the difference between a hash and a checksum?

Terminology. A checksum (CRC32, Adler-32) detects accidental errors but is trivially collidable by an adversary. A cryptographic hash is a checksum with additional security properties that make it resistant to deliberate attacks.

Why is bcrypt limited to 72 bytes?

Bcrypt is derived from Blowfish, whose key schedule uses 72 bytes maximum. Inputs longer than 72 bytes are silently truncated — which can cause security issues if you concatenate a pepper or prefix. For new work, prefer Argon2id which has no such limit.

How often should I rotate the hash algorithm in my app?

Design for algorithm agility from day one — store the algorithm name and parameters alongside each hash (bcrypt and Argon2 do this automatically in their output format). On user login, if the current stored algorithm/params are outdated, rehash the plaintext password with the new parameters and update the database. This enables a zero-downtime migration.

What is pepper and should I use one?

A pepper is a server-side secret added to every password before hashing, stored separately from the database (HSM, env var, Vault). It means a database-only leak does not allow offline cracking. Use a pepper for high-value systems. For most applications, a strong Argon2id with good parameters is sufficient.

Summary and Next Steps

Hash functions are the unsung foundation of modern security. The rules are simple: use SHA-256 or BLAKE3 for integrity and signatures; use Argon2id or bcrypt for passwords; use HMAC-SHA-256 for message authentication; salt everything user-derived; and never trust MD5 or SHA-1 for anything an adversary might touch.

Want to generate a hash right now in your browser — with no data leaving your device? Try our hash generator supporting MD5, SHA-1, SHA-256, SHA-384, SHA-512:

https://stringtoolsapp.com/hash-generator

Related Tools

- Hash Generator — compute MD5/SHA-1/SHA-256/SHA-384/SHA-512 in the browser - Base64 Encoder — for handling binary digests - Password Generator — strong passwords that deserve strong hashing - JSON Formatter — for inspecting API payloads with signed hashes

Explore all tools: https://stringtoolsapp.com