Blogchevron_rightSecurity
Security

MD5 vs SHA-256 — Which Hash Algorithm Should You Use?

"Just use SHA-256" is a fine answer most of the time. The interesting question is when MD5 is still acceptable, when SHA-256 is overkill, and when neither is the right tool.

December 3, 2026·8 min read·Hash any text →

Quick Decision Table

Use caseUse thisDon't use
Detecting accidental file corruptionMD5 / CRC32
Cache key / dedupe key for trusted contentMD5 / xxHash
Verifying download from untrusted mirrorSHA-256MD5, SHA-1
Digital signatures, certificates, JWTSHA-256 / SHA-384MD5, SHA-1
Git-style content addressingSHA-256 (or SHA-1 for legacy)MD5
Storing user passwordsArgon2id / bcrypt / scryptMD5, SHA-*, plain hashes
HMAC for API request signingHMAC-SHA-256HMAC-MD5 (legacy only)

The 4 Hash Use Cases

Cryptographic hash functions are deceptively single-purpose-looking. In reality they serve four distinct jobs, each with different requirements:

Checksum: Detect accidental corruption — bit flips on disk, transmission errors. Only needs to be unique under random noise. Speed matters; collision resistance does not.
Integrity: Detect tampering by an active adversary. Requires collision resistance: nobody can craft two inputs with the same hash.
Password storage: Make brute force expensive. Requires deliberately slow computation, salt, and a memory-hard function. Cryptographic hashes are wrong here — they're too fast.
Digital signatures: Bind a message to a private key holder. Requires collision resistance and pre-image resistance to the strongest currently known attacks.

MD5 — Fast But Broken

MD5 was published in 1992 and produces a 128-bit (16-byte) digest. It is one of the fastest cryptographic hashes ever designed and is still widely used for non-security-critical jobs: ETags, dedupe keys, file fingerprints in build systems, cache invalidation.

MD5 is cryptographically dead. The first published collision attack came in 2004 (Wang et al.); by 2008 researchers were forging trusted SSL certificates with chosen-prefix collisions in under 24 hours on modest hardware. Today, generating MD5 collisions on demand takes seconds on a laptop.

Practical rule: MD5 is fine when both inputs are produced by a trusted party — your own build system, your own dedupe table. MD5 is a security failure when one of the inputs comes from somebody who might want to fool you.

SHA-1 — Deprecated

SHA-1 produces a 160-bit (20-byte) digest. It powered HTTPS for a decade, signed every TLS certificate until 2017, and is still the foundation of Git's content-addressed storage.

In February 2017, Google and CWI Amsterdam announced the "SHAttered" attack: two distinct PDFs with identical SHA-1 digests, produced for roughly $110,000 of cloud GPU time. By 2020, the attack cost had dropped to ~$45,000. Chosen-prefix collisions — strictly stronger than identical-prefix — were demonstrated in 2019.

Browsers stopped trusting SHA-1 certificates in 2017. Git is migrating to SHA-256 (Git 2.29+ supports it; the migration is slow because of ecosystem inertia). New code in 2026 should not use SHA-1 for any security-relevant purpose.

SHA-256 — The Modern Default

SHA-256 is part of the SHA-2 family (Secure Hash Algorithm 2), published by NIST in 2001. It produces a 256-bit (32-byte) digest. After a quarter-century of public scrutiny, no practical collision or pre-image attack has been demonstrated. The best generic attack on SHA-256 is brute force at 2^128 operations for collisions — vastly beyond any plausible adversary, including a state-funded one.

SHA-256 is the foundation of TLS 1.3 certificates, JWT (HS256/RS256/ES256), Bitcoin's proof of work and address derivation, Git's next-generation object IDs, every modern code-signing system, and most cloud-provider request signing (AWS Signature v4, GCP HMAC).

When in doubt, use SHA-256. It is the boring, correct answer for almost every "I need a cryptographic hash" question.

SHA-512 — Bigger ≠ Always Better

SHA-512 is also part of SHA-2 and produces a 512-bit (64-byte) digest. Surprisingly, on 64-bit CPUs it is often faster than SHA-256 — its internal operations are 64-bit, which maps to one register per word, while SHA-256 wastes the upper half.

When does the larger digest actually help? Three cases:

  • Future-proofing against quantum computers — Grover's algorithm halves the effective security of any hash, so SHA-512 still gives 256 bits of post-quantum collision resistance versus SHA-256's 128 bits.
  • HMAC keys longer than 64 bytes — HMAC-SHA-512 has a 128-byte block size, so longer keys aren't pre-hashed.
  • Truncated digests — taking the leading 256 bits of SHA-512 (sometimes called SHA-512/256) is faster on 64-bit CPUs than computing SHA-256 directly and gives the same 128-bit collision resistance.

For everyday hashing where digest length isn't a constraint, both work. If you're writing a new spec in 2026 and want to be conservative against quantum, SHA-384 or SHA-512 is the slightly-paranoid default.

Why Cryptographic Hashes Are NEVER for Password Storage

A modern GPU can compute roughly 100 billion SHA-256 hashes per second. For a typical 8-character ASCII password (about 53 bits of entropy), the entire keyspace is exhausted in under 30 hours on a single rented A100. With 8× A100s, under 4 hours.

Password hashing functions — bcrypt (1999), scrypt (2009), Argon2 (2015, winner of the Password Hashing Competition) — deliberately make this expensive in three ways: a tunable iteration count, mandatory per-user salt, and (for scrypt/Argon2) memory hardness so that GPU and ASIC attacks lose their advantage.

Use Argon2id with parameters tuned to ~250ms on your server (a starting point: m=64MB, t=3, p=1). Bcrypt with cost 12+ is still acceptable. Scrypt remains fine. Anything based on raw SHA-* — even with a salt and millions of iterations (PBKDF2) — is the weakest of the modern options because it isn't memory-hard.

Hard rule: If your code does anything like sha256(password + salt), you have a vulnerability. Use a password hashing library — never roll your own.

Web Crypto API in Practice

Modern browsers and Node.js 20+ ship the same standard crypto.subtle API. No external library needed:

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

await sha256('hello world');
// "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"

// Streaming for large files (Node.js)
import { createHash } from 'node:crypto';
import { createReadStream } from 'node:fs';

async function fileHash(path, algo = 'sha256') {
  const hash = createHash(algo);
  for await (const chunk of createReadStream(path)) {
    hash.update(chunk);
  }
  return hash.digest('hex');
}

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

The Web Crypto API supports SHA-1, SHA-256, SHA-384, and SHA-512. Notably absent: MD5. The browser vendors made the deliberate choice not to expose it, since most legitimate uses can be served by SHA-256 and the tiny minority that genuinely need MD5 (legacy protocols, ETags) can ship a 5-line pure-JS implementation.

Hash any text instantly

MD5, SHA-1, SHA-256, SHA-512 — runs entirely in your browser, no upload.

Open Hash Generator →

Related Tools

MD5 vs SHA-256 — Which Hash to Use?