MD5, SHA-1, and SHA-256 Checksums vs. Password Hashing Explained
By Huzaifa • Published: 2026-10-15 • 6 min read
Why fast cryptographic hash functions like MD5, SHA-1, and SHA-256 serve different jobs in integrity checking, and why storing user passwords requires slow, salted algorithms like Argon2id, scrypt, or bcrypt.
Few topics cause more confusion in web development tutorials than cryptographic hashing. Beginners often learn that "passwords should be hashed, never stored in plain text," and then reach for SHA-256 or MD5 because those functions are built right into standard libraries.
On the surface, a hexadecimal SHA-256 digest looks completely scrambled and irreversible. Yet using raw SHA-256—or worse, MD5 or SHA-1—to store user passwords in a database is a serious security flaw. Understanding why comes down to the fundamental design difference between fast general-purpose digests and slow, salted password hashing functions.
What a Cryptographic Hash Function Does
A cryptographic hash function takes an arbitrary sequence of bytes—whether a three-letter word or a four-gigabyte Linux ISO image—and produces a fixed-length output called a digest or hash. Even a single bit flip in the input changes roughly half of the bits in the output (known as the avalanche effect):
Input: "ToolTux"
SHA-256: 5f2c8d04... (256 bits / 64 hex characters)
Input: "tooltux"
SHA-256: 8a91e41b... (completely different 64 hex characters)
You can observe this behavior interactively in the Hash Generator: type a sentence, toggle a single uppercase letter or trailing space, and watch the MD5, SHA-1, SHA-256, and SHA-512 outputs change completely.
A secure general-purpose cryptographic hash aims for three properties:
- Preimage resistance (one-way): Given a hash output
H, it should be computationally infeasible to work backward mathematically to find an inputMsuch thathash(M) = H. - Second-preimage resistance: Given a specific input
M1, it should be infeasible to find a different inputM2that produces the exact same hash. - Collision resistance: It should be infeasible to find any two distinct inputs
M1 != M2anywhere that collide to the same digest.
Comparing MD5, SHA-1, SHA-256, and SHA-512
Not all digest algorithms still meet those three goals today:
- MD5 (128-bit / 32 hex chars): Practical collision attacks against MD5 have existed for two decades; two different files can be crafted to share the exact same MD5 hash in seconds on a laptop. MD5 is still occasionally used as a non-security checksum to detect accidental network corruption or generate cache keys, but it must never be used for digital signatures, certificates, or security verification.
- SHA-1 (160-bit / 40 hex chars): Demonstrated collision attacks (such as SHAttered) broke SHA-1 collision resistance in practice. Major browsers and certificate authorities retired SHA-1 TLS certificates years ago, and Git has been transitioning object repositories toward SHA-256.
- SHA-256 and SHA-512 (SHA-2 family, 64 and 128 hex chars): Designed by the NSA and standardized by NIST in FIPS 180-4, SHA-256 and SHA-512 remain the workhorses of modern internet infrastructure. They power TLS handshakes, Subresource Integrity (
integrity="sha256-..."on HTML<script>tags), software release verification, JWTHS256/RS256signatures, and content-addressed storage.
If you encounter an unknown digest string in a configuration file, audit log, or CTF exercise, pasting it into the Hash Identifier inspects its character set, prefix structure (such as $2b$ or $argon2id$), and bit length to list the candidate algorithms that match that format.
Why Fast Hashes Are Dangerous for User Passwords
General-purpose hashes like SHA-256 are engineered to be as fast as possible in both CPU instructions (including dedicated SHA-NI hardware instructions) and massively parallel GPU cores. That speed is wonderful when verifying a multi-gigabyte download or signing thousands of API requests per second.
When a database table of password hashes is leaked, however, speed works entirely in the attacker's favor:
- Billions of guesses per second: Because human-chosen passwords come from a tiny, predictable subset of strings, an attacker does not try to "reverse" SHA-256 mathematically. Instead, they feed wordlists, leaked password corpora, and mutation rules into consumer GPUs that compute billions of unsalted SHA-256 hashes per second.
- Identical passwords produce identical unsalted hashes: Without a unique random salt per user, two users who pick the same password have the exact same SHA-256 hex string in the database, allowing precomputed lookup tables (rainbow tables) and batch cracking against every user simultaneously.
Adding a random salt (SHA256(salt + password)) stops precomputed rainbow tables, but it does not slow down the hash function. An attacker targeting a specific high-value account can still test billions of candidates per second against that user's salt.
What Proper Password Storage Uses Instead
Dedicated password hashing functions—also called key derivation functions (KDFs)—solve both problems by combining a cryptographically random per-user salt with deliberate computational cost and memory hardness (requiring kilobytes or megabytes of RAM per guess so GPUs and ASICs cannot run thousands of parallel lanes cheaply):
- Argon2id (Recommended): Winner of the Password Hashing Competition and recommended by OWASP. It blends resistance against GPU cracking (memory hardness) with resistance against side-channel timing attacks. An output string encodes the algorithm, version, memory/time/parallelism parameters, Base64 salt, and hash in one self-contained string:
$argon2id$v=19$m=65536,t=3,p=4$c29tZXJhbmRvbXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG
- scrypt: Another memory-hard KDF built natively into Node.js's
node:cryptomodule (crypto.scrypt), making it a strong zero-dependency choice on Node backends. - bcrypt (
$2b$): A battle-tested adaptive algorithm with a configurable work factor (for example, cost12). Keep in mind two bcrypt specifics: it has less memory hardness than Argon2id, and it truncates inputs at 72 bytes, which matters for long UTF-8 passphrases. - PBKDF2-HMAC-SHA256: Widely required in FIPS-validated environments and available in the browser's Web Crypto API (
SubtleCrypto.deriveBits), though it requires high iteration counts (OWASP recommends 600,000+ iterations for PBKDF2-HMAC-SHA256) because it is CPU-hard rather than memory-hard.
Quick Decision Checklist for Developers
- Verifying file downloads, CDN
integritytags, or cache keys? Use SHA-256 (testable directly in the Hash Generator). - Authenticating webhook payloads with a shared secret? Use HMAC-SHA256 (never plain
SHA256(secret + body), which is vulnerable to length-extension attacks). - Storing user account passwords on a server? Use Argon2id (or
scrypt/bcrypt) with unique random salts—and encourage users to generate high-entropy credentials using a CSPRNG tool like the Password Generator.
Featured Tools Mentioned in This Guide
- Hash Generator — Compute cryptographic hashes (MD5, SHA-1, SHA-256, SHA-512) for any text string instantly.
- Hash Identifier — Identify unknown hash types based on length, character set, and structural signatures.
- Password Generator — Generate strong cryptographically random passwords with custom symbols, numbers, and length parameters.