🧂 Bcrypt Hash Generator & Verifier

Last updated: June 20, 2026

Bcrypt Hash Generator & Verifier

Generate $2b$ hashes with configurable cost, or verify a password against any existing bcrypt hash.

10
Cost 10 = 1,024 iterations (~300ms). Recommended: 10–12 for production.
Verification re-runs the full bcrypt computation. Higher cost factors take longer — this is by design.

Bcrypt Internals: Why It's Still the Right Answer for Password Hashing in 2024

Walk into any security review of a web application built in the last decade and you'll find the same question on the checklist: "Are passwords hashed with bcrypt, Argon2, or scrypt?" Bcrypt, despite being designed in 1999, keeps earning that spot. Understanding precisely why — and understanding what the cost factor actually controls inside the algorithm — turns bcrypt from a black-box dependency into a tool you can reason about confidently.

The Blowfish Cipher at the Core

Bcrypt is not an HMAC, not a PBKDF, and not built on SHA-anything. It uses the Blowfish symmetric cipher — specifically a modified version of the key schedule called Eksblowfish (Expensive Key Schedule Blowfish). Blowfish is a 64-bit block cipher with a variable-length key and a notably slow key setup phase. Most block ciphers are designed so key setup is cheap because you set the key once and encrypt megabytes of data with it. Blowfish inverts that assumption: key setup requires 521 applications of the cipher itself, expanding a short key into eighteen 32-bit P-array subkeys and four 256-entry S-boxes — a total of 4,168 bytes of derived state.

The original Blowfish slow key setup was an accident of elegance. Niels Provos and David Mazieres turned it into a feature. Their 1999 USENIX Security paper introduced bcrypt, which wraps Blowfish's key schedule in a loop repeated 2^cost times. The work factor isn't additive — it's exponential. Every increment of the cost parameter doubles the computation required. Cost 10 means 1,024 complete Blowfish key schedules. Cost 12 means 4,096. Cost 14 means 16,384. This is exactly the property you want in a password hash: you can keep it slow even as CPUs get faster, simply by bumping the cost value stored in the hash itself.

The $2b$ Hash Format, Parsed

A bcrypt hash string like $2b$12$R9h/cIPz0gi.URNNX3kh2OPST9/PgBkqquzi.Ss7KIUgO2t0jWMUW encodes everything needed to verify a future password — no separate salt table required. Breaking it apart:

  • $2b$ — algorithm identifier. The "2b" variant (also found as "2a" in older PHP hashes and "2y" in some PHP implementations) specifies that the password is appended with a null byte before hashing, preventing truncation attacks on certain high-byte characters.
  • 12 — the cost factor. Stored as a two-digit decimal, so valid values run from 04 to 31.
  • R9h/cIPz0gi.URNNX3kh2O — the 22-character bcrypt-base64 encoded salt (128 bits).
  • PST9/PgBkqquzi.Ss7KIUgO2t0jWMUW — the 31-character bcrypt-base64 encoded hash output.

The base64 alphabet used by bcrypt is not standard RFC 4648 base64. It uses the custom alphabet ./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789, which is one of the subtleties that catches developers who try to verify bcrypt hashes by re-implementing just the base64 layer.

The complete 60-character string is self-describing. To verify a password, you extract the cost and salt from the stored hash, run bcrypt with those parameters, and compare the output in constant time. No additional columns in your database, no separate salt storage, no key rotation headaches on the hash format itself — the format is append-only: future parameters just get a new algorithm version string.

The Key Schedule Step by Step

Here is the precise EksBlowfish sequence that runs during every bcrypt hash operation:

  1. Initialize state from the fixed constants derived from the hexadecimal digits of pi — the same constants as the original Blowfish cipher. This gives you a known-good starting P-array and four S-boxes.
  2. XOR the P-array with the password bytes, cycling through the password if it's shorter than the 72-byte limit (bcrypt truncates passwords to 72 bytes — an important limitation).
  3. Run the initial Eksblowfish round: expand the state using the salt, alternating between password and salt as the key material through 2^cost rounds of the standard Blowfish key schedule.
  4. Encrypt the magic string "OrpheanBeholderScryDoubt" (6 × 32-bit words, 64 Blowfish encryptions of each pair) using the final Blowfish state.
  5. Encode the output in bcrypt-base64 and concatenate with the version, cost, and salt.

The critical property is that each step depends on the output of the previous one. There is no shortcut to the final ciphertext that doesn't involve doing all 2^cost key schedules in order. This sequential dependency is exactly what prevents GPU and ASIC attacks from achieving the same parallelism they achieve against MD5 or SHA-256 password hashes.

Why GPUs Don't Like Bcrypt

SHA-256 cracking on a modern GPU can attempt billions of hashes per second because each hash candidate is independent and requires only integer arithmetic that maps efficiently onto GPU shader units. Bcrypt's Blowfish state is 4,168 bytes — far larger than a GPU thread's register file. Each candidate password requires loading and mutating that state through thousands of iterations, causing constant cache misses and memory bandwidth pressure. The result is that bcrypt on a GPU achieves only a small multiple of single-CPU throughput rather than the thousands-of-times speedup you'd see with raw SHA-256.

Argon2 (the 2015 Password Hashing Competition winner) goes further by also requiring large amounts of RAM, making it resistant to both GPU and ASIC attacks simultaneously. For new systems, Argon2id is the current recommendation. But bcrypt remains perfectly acceptable for existing deployments — especially if you use cost 12 or higher.

The 72-Byte Password Truncation Problem

Bcrypt's password input is limited to 72 bytes (not characters — bytes in the UTF-8 encoding). Passwords longer than 72 bytes are silently truncated. This means password1234567890... (73 bytes) and password1234567890... (150 bytes) produce the same hash if the first 72 bytes are identical.

The standard mitigation is to pre-hash the password with a fast hash (typically SHA-256 or SHA-384) before passing it to bcrypt. This converts arbitrarily long passwords into a fixed-size byte string, preventing both the truncation vulnerability and potential denial-of-service attacks where an attacker submits an enormous string hoping bcrypt will still try to process it in full. If you use pre-hashing, be careful not to hex-encode the SHA output — pass the raw bytes or base64-encode them to keep within the 72-byte limit while preserving full entropy. This technique is sometimes called "pepper + prehash" when a server-side secret (the pepper) is also mixed in.

Choosing the Right Cost Factor in Production

The OWASP Authentication Cheat Sheet recommends a cost factor that brings hash generation to at least 100ms on the hardware doing the hashing. As a practical starting point, cost 10 is appropriate for consumer web applications on typical cloud VMs and has been the default in most bcrypt libraries since around 2010. Cost 12 is now reasonable on modern hardware and provides significantly more brute-force resistance. Cost 14 is appropriate for high-value targets like financial services or credential vaults where you can accept slightly longer login latency.

The stored hash includes the cost factor, which means you can perform online cost upgrades without invalidating existing hashes: on each successful login, check if the stored hash uses the old cost, and if so, rehash with the new cost and update the database. Users never notice — the only difference is a slightly longer first login after the upgrade. This makes bcrypt cost migration low-risk in production systems.

Constant-Time Comparison is Not Optional

One detail that bcrypt libraries get right but naive implementations sometimes miss: the comparison of the computed hash against the stored hash must run in constant time, independent of where the first differing byte is. A timing-variable comparison leaks information about how many leading characters of the hash match, which is usable in side-channel attacks against low-latency networks. The correct approach is XOR all bytes together and check if the final accumulated difference is zero. All serious bcrypt libraries implement this — and this tool does too.

FAQ

What is a bcrypt cost factor and what value should I use?
The cost factor (also called the work factor or rounds) is the base-2 logarithm of the number of Blowfish key schedule iterations bcrypt performs. Cost 10 means 2^10 = 1,024 iterations; cost 12 means 4,096. Each increment doubles the computation time. For most web applications, cost 10 is a reasonable minimum. The 2024 OWASP recommendation is to target at least 100ms of hash time on your production hardware, which typically means cost 10–12. Increase the cost over time as servers get faster — bcrypt stores the cost inside the hash string, so existing hashes remain valid while new ones use the higher cost.
Why does bcrypt truncate passwords at 72 characters?
Bcrypt feeds the password into Blowfish's key schedule, which internally cycles through the key bytes. The original Blowfish key setup reads exactly 72 bytes. Any bytes beyond position 72 are never read — they don't affect the output. This is a known limitation of the algorithm, not a bug in any specific implementation. To handle passwords longer than 72 bytes, hash the password first with SHA-256 or SHA-384 and pass the raw binary output (or base64-encoded output) to bcrypt. This is sometimes called pre-hashing and is safe as long as the pre-hash output fits within 72 bytes.
What is the difference between $2a$, $2b$, and $2y$ bcrypt hashes?
$2a$ was the original bcrypt format. A bug discovered around 2011 affected how certain multi-byte UTF-8 characters were handled. $2b$ is the corrected version and is the standard format for new hashes in all modern libraries (Node.js bcryptjs, PHP password_hash, Python passlib, Go's golang.org/x/crypto/bcrypt). $2y$ was a PHP-specific label used during the transition period and is functionally identical to $2b$. For verification purposes, treat $2b$, $2a$, and $2y$ hashes the same — all modern libraries accept all three prefixes, and the computation is identical for the vast majority of passwords.
Is it safe to run bcrypt hashing in the browser?
Yes, for developer testing and tooling purposes. This tool runs the full bcrypt algorithm in pure JavaScript inside your browser — no password ever leaves your device and no network request is made. However, for production login systems, bcrypt hashing should happen on the server, not the client. Running it client-side in production applications would expose your password hashing logic and cost parameters to attackers, and it would allow attackers to pre-hash passwords with a known salt to bypass rate limiting. Browser-based bcrypt is appropriate for testing hashes, verifying migration logic, and educational purposes.
Can I use bcrypt to hash data other than passwords?
Technically yes, but it is not the right tool. Bcrypt is designed specifically for slow, one-way password hashing. Its 72-byte input limit and intentional slowness make it unsuitable for general-purpose hashing of arbitrary data, API keys, or file contents. For those use cases, use SHA-256 or SHA-3 via the Web Crypto API. For API keys and tokens that need to be verified without revealing the original value, HMAC-SHA256 with a server-side secret is the standard approach. Bcrypt's deliberate slowness is a feature for passwords and a liability for everything else.
What is salt-and-pepper storage and how does bcrypt fit in?
Salt is a random value unique to each password that is stored alongside the hash and prevents rainbow table attacks. Bcrypt generates and stores its own 128-bit salt automatically — you don't manage it separately. Pepper is a server-side secret added to every password before hashing, stored in application configuration or a secrets manager rather than in the database. If an attacker steals the database but not the application secrets, they cannot verify any password guesses even if they know the bcrypt cost and salt. The typical pattern is: hashed_value = bcrypt(password + pepper, cost). This tool demonstrates the bcrypt layer; the pepper layer happens upstream in your application code.