Back to articles index
Format comparisons

SHA-256 vs MD5 vs SHA-1 — which hash algorithm should you pick?

Compare three hash algorithms used for file integrity, password storage, and digital signing by collision resistance, speed, and practical security. Explains why MD5 and SHA-1 are considered broken today.

Four axes that decide the hash

Picking a hash function is not “rank them by strength and take the top one”. Collision resistance — whether an attacker can craft two different inputs with the same digest — is critical for tamper detection and signatures, but irrelevant for some uses. Output size (128 / 160 / 256 / 512 bits) drives storage, URL length, and key design. Throughput matters for pipelines that hash millions of objects: backup integrity checks, CDN ETag generation, deduplication. Standards alignment decides whether the other side — a TLS certificate authority, a Git object database, a vendor’s checksum file — will accept what you produce.

“Newer is better” points in the right direction but is not actionable on its own. Replacing MD5 with SHA-256 does not automatically make a system safe — using SHA-256 to store raw passwords is just as exposed as using MD5 for the same job. Picking without naming the threat model (who is the attacker, what are they trying to forge) is how teams end up reaching for SHA-256 in the one place where Argon2id is required.

Side-by-side comparison

PropertyMD5SHA-1SHA-256
Output length128 bit (16 byte)160 bit (20 byte)256 bit (32 byte)
Hex length32 chars40 chars64 chars
ConstructionMerkle-Damgård (Rivest, 1991)Merkle-Damgård (NIST, 1995)SHA-2 family (NIST, 2001)
Collisions found2004 (Wang); practical attacks since2017 (Google SHAttered, ~110 GPU years)None to date
Recommended useCasual integrity checks onlyCompatibility with legacy systems onlyTamper detection, signing, TLS, blockchain
Speed (relative)1.0 (fastest baseline)~1.2× slower~1.5-2× slower
StandardsRFC 1321 (deprecated for security)NIST SP 800-131A: retire by 2030NIST FIPS 180-4, current

MD5 has been collision-broken since Wang et al. in 2004, with Sotirov et al. forging a real Certificate Authority signature in 2008 — for tamper detection it is dead. SHA-1 fell in 2017 when Google and CWI produced “SHAttered”, two distinct PDFs with the same SHA-1, and browsers have rejected SHA-1 TLS certificates ever since. SHA-256, part of the SHA-2 family, still has no public practical collision as of 2026. For completeness, BLAKE2 / BLAKE3 are faster than SHA-256 with comparable security, and SHA-3 (Keccak) is standardised as a structurally different backup family.

Choosing by situation

File integrity / release artefacts: SHA-256. The usual workflow is publishing a *.sha256 next to the download and recomputing locally to confirm a match. Treat MD5 and SHA-1 as good enough to catch bit-rot during a download, but not for adversarial scenarios where someone might swap the file mid-transit.

Password storage: never a plain hash. Using SHA-256 raw is no safer than using raw MD5 — rainbow tables and GPU/ASIC brute force make both fall fast. Use a Key Derivation Function (KDF): Argon2id (the current recommendation), bcrypt, or scrypt, always salted per user. SHA-256 may exist inside the construction, but the application code should never invoke it directly to store a credential.

Git object IDs / existing protocol compatibility: SHA-1 remains in use (Git is gradually transitioning to SHA-256). When an upstream API hands you an MD5 or SHA-1, match it — but there is no reason to design new systems around either.

TLS certificates, code signing, JWT signatures: SHA-256 or stronger. SHA-1 certificates are rejected by modern browsers. JWT uses HS256 / RS256 / ES256 — the trailing 256 is SHA-256.

Short identifiers (cache keys, ETags): if collision resistance is not part of the threat model, MD5 is fine for raw speed. The risk is that the identifier later gets repurposed for tamper detection without anyone updating the algorithm — defaulting to SHA-256 from the start avoids that quiet migration.

Computing hashes inside the browser

For ad-hoc hashing of files and strings, hash-generate computes MD5, SHA-1, SHA-256, SHA-512, and friends in a single pass. Typical jobs include verifying a release ZIP against a published checksum, double-checking a downloaded installer, and comparing two log lines for equality without leaking content to a third-party service.

Three things to keep in mind. (1) Same input, same output: verification is byte-for-byte comparison between the published digest and the one you recompute locally — there is nothing else to “verify”. (2) Line endings matter: a text file read as CRLF and the same file as LF produce different hashes. Git’s core.autocrlf on Windows and editors that add or remove BOMs are common sources of “but it matched before” confusion. (3) Constant-time comparison: when you compare digests in application code, use a constant-time comparison (crypto.timingSafeEqual or equivalent) instead of ===, which can leak the prefix length through timing. The browser implementation is published on GitHub, and the DevTools Network tab confirms that the file content stays inside the page while it is being hashed.