What is bcrypt?
bcrypt is a password hashing function designed by Niels Provos and David Mazières and presented in 1999. It was built for one job: storing password verifiers so that every guess against a stolen hash costs an attacker real time. It generates and embeds a salt automatically, and its cost factor can be raised over the years as hardware gets faster, which is why its authors described it as adaptable to the future. It became the default password scheme in OpenBSD and remains one of the most widely used options in web frameworks.
How bcrypt works
bcrypt is built on Eksblowfish, an expensive key-setup variant of the Blowfish cipher. Blowfish normally runs its key schedule once; bcrypt runs it 2^cost times, alternately mixing in the password and a 128-bit salt, then uses the resulting cipher state to encrypt a fixed 24-byte string 64 times. The cost is an exponent, so raising it by one doubles the work:
| Cost | Key-schedule repetitions | Work compared with cost 10 |
|---|---|---|
| 10 | 1,024 | 1x |
| 12 | 4,096 | 4x |
| 14 | 16,384 | 16x |
Each computation also reads and rewrites about 4 KB of cipher state constantly. That isn't memory-hard in the way scrypt and Argon2 are, but it makes bcrypt noticeably less efficient on GPUs than fast hashes or PBKDF2.
Reading a bcrypt hash
A stored bcrypt value is a 60-character string that carries everything needed to check a password later: $2b$12$ followed by 22 characters of salt and 31 characters of hash.
- $2b$ is the version. Other systems show $2a$ or $2y$, labels that came from specification revisions and fixes to bugs in particular implementations.
- 12 is the cost.
- The next 22 characters encode the 128-bit salt and the last 31 encode the hash, in bcrypt's own Base64 alphabet.
Because the cost is stored with each hash, a site can raise it for new passwords and rehash existing ones when users next sign in. In Python, bcrypt.hashpw(password, bcrypt.gensalt(rounds=12)) produces such a string and bcrypt.checkpw() verifies a password against one.
The 72-byte limit
bcrypt uses at most the first 72 bytes of its input and ignores the rest. That can be fewer than 72 characters, since accented letters and emoji take two to four bytes each in UTF-8. Many libraries truncate silently, so two long passphrases that differ only after byte 72 verify as the same password; some newer versions reject longer input instead. The limit bites hardest when bcrypt is used for more than a single password. In 2024 Okta disclosed a flaw in a bcrypt-based login cache key built from a user ID, username and password: with a username of 52 characters or more, the password could fall beyond the limit, so under certain conditions a cached login succeeded without the right password. Designs that need longer inputs either cap passwords at 72 bytes or first apply a keyed hash and encode the result, for example in Base64, so stray null bytes can't cut the input short.
bcrypt vs. Argon2 vs. PBKDF2
All three are slow on purpose, but they differ. Argon2id adds a tunable memory cost and is OWASP's first choice for new systems. PBKDF2 needs almost no memory, so GPUs attack it efficiently, but it is NIST-approved, which matters where FIPS-validated cryptography is required. bcrypt sits between them: well studied, available everywhere and reasonably resistant to GPUs, but not FIPS-approved and limited to 72 bytes. OWASP lists it for legacy systems where Argon2id and scrypt aren't available, with a cost of at least 10. A general-purpose hash such as SHA-256 is no substitute for any of them, even with a salt, because it is designed to be fast.
bcrypt on the CompTIA Security+ exam
SY0-801 no longer lists key stretching, the technique bcrypt implements, as a separate item. bcrypt belongs to secure password storage, which is taught with salting and hashing algorithms under objective 1.3, the cryptographic solutions objective. Wording such as "make offline cracking of stolen password hashes slower" or "the BEST way to store user passwords" points to a salted, deliberately slow algorithm such as bcrypt or Argon2id. Distractors include salted SHA-256 or SHA-512, which are strong but fast, encrypting passwords with AES, which is reversible, MD5, and account lockout, which can't slow guessing against a copied database.