DevTools Hub

Search tools

Search for a developer tool

Password Hashing Explained

A well-built site never has your actual password after you set it — only a hash of it. That much is common knowledge. What's less obvious is that "hash it" is nowhere near enough on its own: the same fast, general-purpose hash functions that are perfect for checksums and fingerprints are actively dangerous for passwords, and using one is one of the most common real-world security mistakes.

Why SHA-256 (or MD5, or SHA-512) is the wrong tool

General-purpose hash functions are built to be fast — hashing a large file in milliseconds is a feature. That's exactly backwards for a password: speed is what lets an attacker who steals your password database try billions of guesses per second on commodity GPU hardware. Combine that with how predictable real human passwords are — dictionary words, names, keyboard patterns, minor variations of "password123" — and a fast hash function turns a stolen database into a solved one within hours, not because the hash function is broken, but because it was never designed to resist this kind of attack in the first place. See MD5 vs SHA-256 vs SHA-512 for how fast these algorithms actually are — the same speed that makes them great for checksums makes them a liability here.

Salting: necessary, but not sufficient

A salt is a random value generated per password and stored alongside its hash. Without one, two users with the same password get the same hash, and an attacker can precompute a rainbow table — a lookup table mapping common passwords to their hashes — once, and reuse it against every stolen database that used the same hash function. A salt defeats precomputation: the attacker now has to attack each hash individually, since the same password produces a different hash for every user.

What salting doesn't do is slow anything down. A salted SHA-256 hash is still exactly as fast to compute as an unsalted one, which means brute force and dictionary attacks against any individual account are just as cheap as before. Salting solves the "attack everyone at once" problem, not the "attack one account fast" problem — that second problem needs a fundamentally different kind of algorithm.

The fix: deliberately slow hashing

Password hashing algorithms are built around the opposite goal of a checksum: make each individual guess expensive, on purpose, in a way that's tunable as hardware gets faster over time. A few thousand hashes per second is irrelevant friction for a real login (one hash, once, per attempt) but devastating for an attacker trying billions of guesses against a stolen database.

  • bcrypt (1999) — built on the Blowfish cipher, with a tunable cost factor that exponentially increases the number of internal rounds. Widely supported and battle-tested, though purely CPU-bound, which makes it somewhat more parallelizable on GPUs than memory-hard alternatives. One real gotcha: bcrypt silently ignores any password bytes past 72 — a rarely-hit but genuine limitation worth knowing about.
  • scrypt (2009) — adds memory-hardness on top of CPU cost: computing it requires a large, tunable amount of RAM per guess. GPUs have thousands of compute cores but comparatively little memory per core, so a memory-hard function narrows the parallelization advantage that makes GPU cracking so effective against CPU-only algorithms.
  • Argon2 (2015) — winner of the Password Hashing Competition and the current default recommendation. It exposes three independent cost parameters — memory, time, and parallelism — tuned separately. The Argon2id variant is the generally recommended mode, balancing resistance to GPU/ASIC cracking with resistance to side-channel attacks.
  • PBKDF2 (2000, NIST-approved) — repeatedly applies a standard hash function (commonly SHA-256) tens or hundreds of thousands of times. Legitimate and still common (WPA2, iOS/Android keychains), but purely iteration-based with no memory-hardness, which makes it the weakest of the four against GPU and ASIC attacks. A reasonable choice when a platform mandates NIST-approved primitives; not the first choice otherwise.

What this looks like in practice

You never call a raw hash function directly for this. A library implementing one of the algorithms above handles salt generation, encodes the cost parameters into the stored value itself (so they can be tuned upward later without breaking old hashes), and provides a verify(password, storedHash) function that recomputes the hash with the stored salt and parameters, then compares the result using a constant-time comparison — a plain === string comparison can leak timing information about how many characters matched, which is exactly the kind of detail a well-designed library handles for you so you don't have to think about it.

Common mistakes worth avoiding

  • Using a raw hash function, salted or not. MD5, SHA-1, SHA-256, and SHA-512 are all wrong here, regardless of how many times you loop-and-rehash them by hand — that's reinventing a weaker, unaudited version of PBKDF2.
  • Reversible encryption instead of hashing. Encrypting passwords with a symmetric key means anyone who obtains that key — from a config leak, a compromised server, an insider — recovers every password at once. A one-way hash has no equivalent single point of failure.
  • Hand-rolling the comparison. Always use the algorithm library's own verify function rather than comparing hash strings yourself.
  • Picking cost parameters once and never revisiting them. Hardware gets faster; a cost factor that was solid five years ago may not be today. Recommended parameters shift over time — checking current guidance (OWASP's cheat sheet series is a reliable source) beats hardcoding a number you read once.

Where this site's hashing tools fit in

Every hashing tool on this site — Hash Generator, Hash Verifier, Checksum Generator, and File Hash Calculator — computes general-purpose, fast hashes: exactly right for verifying file integrity or fingerprinting text, exactly wrong for password storage, for all the reasons above. Password hashing has to happen server-side with a maintained bcrypt/scrypt/Argon2 library, never client-side and never with a general-purpose hash function. What you can do client-side is generate strong source material for a password in the first place — see Password Generator, which runs entirely in your browser using the Web Crypto API's cryptographically secure random number generator.

Related tools