Both SHA-256 and bcrypt are cryptographic functions that transform a password into a fixed-length string of characters. Both are one-way — you can’t reverse the output to recover the original input. To a non-specialist, they look like they solve the same problem.
But using SHA-256 for password storage is a serious security mistake. Understanding why requires understanding what each function was designed to do and, crucially, how fast it runs.
What SHA-256 was designed for
SHA-256 is a member of the SHA-2 family, designed by the NSA and standardised by NIST. It was built for speed and data integrity. Its job is to produce a unique fingerprint of a piece of data so you can verify that data hasn’t been tampered with.
When you download software and the developer publishes a SHA-256 checksum, you can verify the download hasn’t been corrupted or modified by computing the checksum yourself and comparing. That process needs to be fast — you might be hashing gigabytes of data.
SHA-256 is extremely good at this. A modern GPU can compute around 10 billion SHA-256 hashes per second.
What bcrypt was designed for
bcrypt was designed in 1999 specifically for password hashing. Its designers understood the core requirement: password hashing should be deliberately slow.
The reasoning is simple. Legitimate systems hash a password once when a user logs in. That takes a few milliseconds at most — imperceptible to the user. Attackers, however, need to hash millions or billions of candidates to crack a stolen hash. If each hash takes 100ms instead of 0.0000001ms, the attacker’s task goes from feasible to practically impossible.
bcrypt has a cost factor (sometimes called work factor) that controls how slow it is. The current recommended cost factor of 12 means bcrypt performs 2^12 (4,096) internal iterations. A modern server can compute roughly 20–100 bcrypt hashes per second at cost factor 12. An attacker faces the same constraint.
The numbers side by side
The difference is not marginal. It is the difference between a password database that can be fully cracked in seconds and one that would take centuries for all but the weakest passwords.
What about salting SHA-256?
A common response to the speed problem is: “but we salt the hashes.” A salt is a random value added to each password before hashing, ensuring that two users with the same password get different hashes. Salting prevents precomputed rainbow table attacks.
Salting SHA-256 is better than unsalted SHA-256. It is still not good enough. The attack model being discussed is not rainbow tables — it’s brute force against individual hashes. Salting doesn’t slow down brute force. An attacker simply runs their 10 billion guesses per second against each hash individually, incorporating the salt.
Salting is a necessary but not sufficient defence. Speed is the other necessary component, and only a deliberately slow algorithm provides it.
bcrypt, scrypt, Argon2: which to use in 2025
bcrypt is battle-tested and supported everywhere. It has one limitation: it truncates passwords at 72 bytes, which is rarely a practical issue.
Argon2 is the current OWASP recommendation and the winner of the Password Hashing Competition in 2015. It is resistant to GPU attacks because it requires significant memory, not just computation — and memory is harder to parallelise than raw hash computation. Use Argon2id if your language or framework supports it.
scrypt is similar to Argon2 in its memory-hardness and is well-supported. Either is an appropriate choice.
Where SHA-256 does belong
SHA-256 is the right tool for many things — just not password storage:
- File integrity verification. Checking that a downloaded file matches its published checksum.
- Digital signatures. Signing a hash of a document is faster and mathematically equivalent to signing the document itself.
- HMAC authentication. Verifying that an API request or JWT token hasn’t been tampered with in transit.
- Generating unique identifiers. Hashing content to create a deterministic ID for deduplication.