bcrypt is a password hashing function built on the Blowfish cipher that is deliberately slow, automatically salts each password, and exposes a tunable cost factor so you can increase its computational expense as hardware improves. It is one of the most widely deployed and battle-tested ways to store passwords securely. bcrypt exists specifically to make brute-force guessing expensive, which is exactly what general-purpose hashes fail to do.
Key takeaways
- bcrypt is a slow, salted password hashing function designed to resist brute-force attacks.
- It generates a random salt automatically and embeds it in the output, so you store one string.
- The cost factor controls how expensive each hash is; raise it over time as hardware speeds up.
- bcrypt only uses about the first 72 bytes of input, an important limitation to handle.
- Verification uses the library’s constant-time compare function, never a manual string equality check.
- bcrypt remains secure today; Argon2id is the modern alternative for new systems.
What is bcrypt and how does it work?
bcrypt was created to solve a specific problem: ordinary cryptographic hashes are fast, and speed helps attackers who want to try billions of password guesses. bcrypt is intentionally slow. It derives its key schedule from the Blowfish cipher through an expensive setup step that is repeated many times according to a configurable cost.
Each time you hash a password, bcrypt creates a random salt, mixes it with the password, runs the costly derivation, and returns a single encoded string containing the algorithm version, the cost, the salt, and the resulting hash. Because everything needed to verify a password is embedded in that string, storage and verification are simple and hard to get wrong.
What is the bcrypt cost factor?
The cost factor, sometimes called the work factor or rounds, is the number that controls how much work bcrypt does. It is logarithmic: increasing the cost by one roughly doubles the time required to compute a hash. This lets you dial in how long each hash takes.
The goal is to choose the highest cost your servers can tolerate without harming legitimate login performance. A hash that takes a fraction of a second for your server is a serious obstacle for an attacker trying to test enormous numbers of guesses. As hardware gets faster over the years, you raise the cost factor to keep pace. Because it is tunable, bcrypt can stay effective long after it was first deployed.
What does a bcrypt hash string look like?
A bcrypt hash is a compact, self-describing string. It typically looks like this:
$2b$12$R9h/cIPz0gi.URNNX3kh2OPST9/PgBkqquzi.Ss7KIUgO2t0jWMUW
The parts, separated by $, are:
2bis the algorithm version identifier.12is the cost factor.- The next 22 characters encode the salt.
- The remaining characters are the hash itself.
Because the version, cost, and salt all live inside the string, verifying a password requires nothing but this stored value and the user’s input.
How do you use bcrypt correctly in code?
You should always use a well-maintained bcrypt library rather than implementing it yourself. The pattern is the same across languages: hash on registration, compare on login. A representative example using a common library interface:
// hashing a new password
const hash = await bcrypt.hash(plaintextPassword, 12);
storeInDatabase(hash);
// verifying at login
const ok = await bcrypt.compare(submittedPassword, storedHash);
if (ok) { grantAccess(); }
Notice you pass the cost (12) only when hashing; when verifying, the cost and salt are read back out of the stored hash automatically. Always use the library’s compare function, which performs a constant-time comparison to avoid timing side channels. Never compare hashes with a plain equality operator.
What is the 72-byte password length limitation?
bcrypt has a well-known quirk: it only processes roughly the first 72 bytes of the input password. Anything beyond that is ignored. For most passwords this never matters, but it creates two pitfalls to guard against.
First, very long passphrases are silently truncated, so two long passwords sharing the same first 72 bytes would be treated as identical. Second, because the limit is measured in bytes, multibyte UTF-8 characters consume the budget faster than ASCII. A related historical concern is that some older bcrypt implementations mishandled null bytes, causing premature truncation. A common, robust mitigation when you must support arbitrarily long inputs is to pre-hash the password with a secure hash and then feed the result to bcrypt, ensuring a fixed-length input. If you do this, apply it consistently and be aware of the tradeoffs.
How does bcrypt compare to other password hashes?
| Algorithm | Type | Memory-hard | Notes |
|---|---|---|---|
| bcrypt | Slow, salted | No | Mature, widely supported, tunable cost |
| scrypt | Slow, salted | Yes | Resists GPU/ASIC attacks via memory use |
| Argon2 | Slow, salted | Yes | Modern winner of the Password Hashing Competition |
| PBKDF2 | Slow, salted | No | Standardized and common in compliance settings |
bcrypt’s main structural difference from scrypt and Argon2 is that it is not memory-hard, so it offers less resistance to attackers using highly parallel GPU or ASIC hardware. It remains strong in practice, but memory-hard functions raise the cost of specialized cracking rigs.
How do you migrate or upgrade bcrypt cost factors?
Because attacker hardware improves, the cost factor you chose years ago may become too low. You cannot re-hash a password you do not know, so upgrades happen at login. When a user successfully authenticates, check the cost stored in their hash; if it is below your current target, transparently re-hash the just-verified plaintext with the higher cost and update the stored value.
This same technique lets you migrate away from bcrypt entirely. On successful login, if the stored hash uses the old scheme, re-hash the verified password with your new algorithm such as Argon2id and replace it. Over time, active users are seamlessly upgraded. For dormant accounts, you can force a password reset. This gradual, login-triggered rehash pattern is the standard way to evolve password storage without knowing anyone’s plaintext.
Is bcrypt still safe to use?
Yes. bcrypt continues to be a respected and secure choice when configured with a strong cost factor and used through a reputable library. Its long track record means its behavior is well understood and its implementations are mature. For brand-new systems, security guidance increasingly points to Argon2id as the first recommendation because of its memory-hardness, with bcrypt and PBKDF2 as solid, widely supported alternatives. What matters most is that you use one of these purpose-built, slow, salted functions rather than a fast general-purpose hash for passwords.
Frequently asked questions
Is bcrypt still secure in modern applications?
Yes. bcrypt remains a solid, widely trusted choice for password hashing when configured with an appropriate cost factor, though Argon2 is often preferred for new projects.
Does bcrypt handle salting for me?
Yes. bcrypt generates a random salt automatically and embeds it in the output hash string, so you store a single self-describing value.
What is the bcrypt 72-byte limit?
bcrypt only considers roughly the first 72 bytes of the input. Longer passwords are effectively truncated, which can be a security surprise if not handled.
What is the cost factor in bcrypt?
It is a work parameter that sets how many rounds bcrypt performs. Each increment roughly doubles the computation time, making brute force slower.
Should I use bcrypt or Argon2?
Both are strong. Argon2, especially Argon2id, is the modern first choice and is memory-hard; bcrypt is a well-proven, widely supported alternative.
Do I need to store the salt separately with bcrypt?
No. The salt is contained within the bcrypt hash string itself, so you only store that one string in your database.
How do I verify a password with bcrypt?
Pass the plaintext and the stored hash to the library’s compare function, which extracts the salt and cost, recomputes, and compares in constant time.