AnyHash
Skip to content

bcrypt Hash & Verify

Generate a salted bcrypt hash of any password — or verify an existing hash — entirely in your browser. Each hash embeds its own random salt and cost factor, so nothing needs to be stored server-side to check it again later.

bcrypt hash

 

Enter a password to generate a salted bcrypt hash.

Code snippets

Generate bcrypt in your language

import bcrypt from "bcryptjs"; // or "bcrypt"

const hash = await bcrypt.hash("password", 10);
console.log(hash);
// $2b$10$... — the salt is random, so every run differs

const ok = await bcrypt.compare("password", hash);
console.log(ok); // true

bcrypt produces a 60-character string that encodes the version, cost factor, salt, and hash. The output changes on every call because the salt is randomly generated.

How bcrypt works

bcrypt derives its strength from the Blowfish key schedule, which it re-runs thousands of times. Each hash starts with a random 128-bit salt and embeds the cost factor — so the same password produces a different hash every time, and verification simply re-runs the algorithm with the stored parameters.

The cost factor doubles the work with every increment: cost 10 runs ~1,000 rounds, while cost 12 runs ~4,000. That deliberate slowness is what makes cracking a stolen hash database prohibitively expensive.

bcrypt best practices

  • Use a cost factor of 10 or higher on modern hardware
  • Never truncate input yourself — but stay under the 72-byte limit
  • Store only the hash string; it contains the salt and cost
  • Pair bcrypt with a strong password policy and rate limiting

New systems: consider Argon2id, the 2015 password-hashing competition winner and today's top recommendation.

Algorithm guide

bcrypt explained

What is bcrypt?

bcrypt is a password-hashing function designed by Niels Provos and David Mazières in 1999, presented at USENIX and adopted as the default password hashing scheme for OpenBSD. It was built to solve a specific problem that MD5 and SHA-based schemes did not: making the hash expensive to compute. Where MD5 hashes billions of values per second on modern GPUs, a single bcrypt hash at a reasonable cost factor takes a fraction of a second of CPU time on a single core — by design.

bcrypt is not a general-purpose hash function. It is a key-derivation function (KDF) built on top of the Blowfish cipher, deliberately reusing Blowfish's expensive key schedule as the computational bottleneck. Every bcrypt output includes a random 16-byte salt, the cost factor, and the derived key, all encoded in a single 60-character string that self-describes its own parameters. That encoding — $2b$<cost>$<salt>$<hash> — is one of the reasons bcrypt has survived two decades of operational use: a system that only needs to store a string can verify passwords without any separate metadata.

How bcrypt works, step by step

1. The EksBlowfish key schedule

Blowfish initializes its sixteen 18-entry P-array and four 256-entry S-boxes from the digits of π, then encrypts the P-array entries using a key. bcrypt's variant — called eksblowfish — does something different: it initializes the P-array and S-boxes from π, then iteratively encrypts the P-array using the salt and password in alternating passes. This is the expensive part: the key schedule is re-run 2cost times, where the cost is stored right in the output string.

2. Encrypting the magic string

After the key schedule completes, bcrypt encrypts the static string "OrpheanBeholderScryDoubt" (sixteen bytes of known plaintext) three times with the derived key, producing a 24-byte value that is then compressed into the final 31-character hash portion of the output.

3. Output encoding

The full 60-character string breaks down as follows:

$2b$ 10$ InnoU1I9E53pJR7Ckm3pEuw6rFE2yXXIBJHbp8VDcUli4ySKsEqRu
  • 2b — the bcrypt version (2a was the original; 2b is the current standard)
  • 10 — the cost factor (encoded as a two-character integer)
  • InnoU1I9E53pJR7Ckm3pEu — the 22-character Base64 encoding of the 16-byte salt
  • w6rFE2yXXIBJHbp8VDcUli4ySKsEqRu — the 31-character encoding of the derived key

The entire hash is self-contained: the salt and cost factor needed to verify a password are baked into the string itself, which means a system storing bcrypt hashes needs no additional salt columns, no configuration, and no versioning scheme.

The 72-byte limit every developer should know

bcrypt internally treats the password as a key for the Blowfish cipher, which has a maximum key length of 72 bytes. When a password exceeds 72 bytes, every byte after the 72nd is silently discarded. This page detects and warns you when this happens, but the real fix is upstream: long passwords should be truncated or hashed down to 72 bytes before they reach bcrypt.

A common pattern in legacy systems is to run SHA-256(password) first — producing a 32-byte fixed-length string — and then bcrypt that output. This removes the 72-byte limitation and guarantees every password contributes at least 256 bits of entropy. The tradeoff is that the SHA-256 step is its own collision surface, but since passwords are typically low-entropy strings, the practical risk is minimal compared to the alternative of silent truncation.

Choosing the right cost factor

The cost factor determines how many times the key schedule iterates: cost n means 2n rounds. Each increment doubles the computational cost. On most modern hardware the guideline is to pick the highest cost factor that keeps verification under about 250 milliseconds for a single login attempt.

CostRoundsApprox. costTypical time (2024 desktop)
8256Low~15–25 ms
101,024Medium (OWASP minimum)~60–100 ms
124,096High~250–400 ms
1416,384Very high~1–2 s
1665,536Extreme~4–8 s

Cost 10 is the OWASP minimum. For new systems on modern servers, cost 12 gives a meaningful security margin without creating unacceptable login latency. Cost 14 is reasonable for batch or background jobs where latency does not affect user experience. Anything above 16 risks denial-of-service at scale and should only be used with a carefully measured threat model.

bcrypt vs MD5 / SHA-256 vs Argon2id vs scrypt vs PBKDF2

bcryptPBKDF2-HMAC-SHA-256scryptArgon2id
Year1999200020092015
Deliberate costCPU (iterations)CPU (iterations)CPU + memoryCPU + memory + threads
GPU/ASIC resistanceModerateLowHighVery high
Library availabilityEvery major languageEvery major languageMost languagesGrowing (most languages)
OWASP recommendationAccepted (legacy)AcceptedAcceptedRecommended
72-byte input limitYesNoNoNo

The table tells the migration story clearly: Argon2id is the strongest choice, followed by scrypt for memory-constrained environments, PBKDF2 where compliance mandates it, and bcrypt as the battle-tested survivor. All four are vastly better than hashing a password with plain SHA-256, which offers zero resistance to high-throughput GPU attacks.

Why bcrypt is still a solid choice

Despite being the oldest option in the table, bcrypt has a crucial operational advantage: every major platform ships a well-tested bcrypt library. PHP, Python, Ruby, Node.js, Go, Rust, Java, and C# all have native or near-native bcrypt bindings, which means moving to bcrypt rarely requires architectural changes.

The 72-byte limit is well-documented, and pre-hashing with SHA-256 lets bcrypt process longer inputs. The cost factor is tunable in a straightforward way. The output encoding is self-describing. These operational properties — more than raw cryptographic superiority — are why bcrypt remains the default in Laravel, Django, Rails, Express, and countless production authentication stacks in 2026.

The recommendation is not to stay on bcrypt forever; it is that replacing bcrypt with Argon2id should be a conscious migration, not a panic. For systems where bcrypt is already deployed and audited, the security benefit of migrating is small compared to the risk of introducing a subtle implementation bug in the new path.

How the AnyHash bcrypt tool works

  • Pure JavaScript, no Web Crypto. The Web Crypto API does not expose bcrypt, so the hash is computed using bcryptjs, a widely-used pure-JS Blowfish implementation specifically designed for password hashing.
  • Auto-generated salt. Every time you type a password, the tool generates a fresh cryptographically random 16-byte salt via crypto.getRandomValues and embeds it in the output string. The same password produces a different hash on every run — this is by design.
  • Debounced computation. Keystrokes schedule a new hash after 240 ms, so the UI stays responsive. At cost 10, the computation completes in roughly 60–100 ms on a modern laptop; at cost 16, the status bar shows a progress indicator while the computation runs in the background.
  • 72-byte warning. The tool counts the UTF-8 byte length of your input before hashing and displays a clear warning when the limit is exceeded, so there is no silent truncation.
  • Hash / Verify tabs. The verify tab accepts a password and a bcrypt hash string, re-derives the key from the hash's embedded parameters, and reports whether the two match. No data is transmitted to a server at any point.

Verification, deep dive

The verify tab in this tool does exactly what a production auth system does: it reads the version, cost, and salt from the hash string, runs the EksBlowfish key schedule with those parameters, derives the candidate key, and compares it against the stored key byte by byte. Because the cost factor is embedded in the hash, a system can rehash passwords at a higher cost over time without resetting any stored credentials — every verification automatically runs at the stored cost.

If you want to confirm this, copy any hash you generate and paste it into a different bcrypt library — Python's bcrypt.checkpw(), for instance — with the same password. The result will always be True. The hash encoding is portable across every standards- compliant bcrypt implementation.

Migrating from bcrypt to Argon2id

If you are planning a migration, the recommended approach is a compare-and-upgrade pattern: when a user logs in with the correct password, rehash the password under Argon2id and store the new hash alongside the old one. This way, each user migrates on their next login without a forced password reset. New accounts and password changes should be hashed with Argon2id from the start.

The AnyHash Argon2id tool lets you experiment with parameters — memory, iterations, and parallelism — against the same password, so you can benchmark different settings before committing to a configuration in production.

$2a, $2b, $2y — the version prefixes

A bcrypt hash string embeds its own version marker. The first element after the leading $ identifies which implementation produced the hash — and, surprisingly, this matters for interop:

  • $2a$ was the original marker, added by the OpenBSD reference implementation and adopted by almost every library. A historical 2003 bug in OpenBSD's original implementation mishandled 8-bit (non-ASCII) bytes, but modern $2a$ implementations are correct — the marker stuck for compatibility.
  • $2b$ was introduced in 2011 by OpenBSD to fix that historic bug formally. It signals “correct handling of 8-bit passwords” and is the marker most contemporary libraries generate today (including the Python bcrypt package and the bcryptjs library this page uses). A $2b$ hash validates with any correct bcrypt implementation regardless of prefix.
  • $2y$ is a PHP-specific alias that signals the PHP fix for the same bug. It is fully interoperable with $2a$ / $2b$ in practice; PHP's own password_hash() generates $2y$ by default.

The money takeaway: treat the version prefix as metadata, not as something to compare exactly. A verify function that rejects hashes merely because the prefix differs (e.g. accepting only $2a$, or only $2b$) breaks 15 years of deployed passwords for no security gain. The password that validates against a $2b$ modern hash will validate against a standards-compliant verifier that accepts any of the three markers.

The economics of the cost factor

The cost factor c means bcrypt runs its key schedule 2c times. That exponential is the lever that keeps old hashes safe as hardware improves: each increase of 1 doubles the work, and each doubling compounds over the years a password stays in the database.

Attack economics make the trade-off concrete. Off-the-shelf GPU rigs today crack bcrypt at roughly tens-of-thousands to hundreds-of-thousands of guesses per second at cost 10 (per-hash work scales with the cost you choose). Cost 11 halves that throughput; cost 12 quarters it, and so on. Compare this with a fast digest like SHA-256, which GPU rigs test at trillions of hashes per second — the margin between “transparently weak” and “practically resistant” is exactly the memory-free, deliberately slow design that bcrypt imposes.

The right cost factor is nevertheless not “the highest available” — it is the highest your real login path tolerates in aggregate. A million active users don't share the cost of one hash; every login, password reset, and session re-auth pays it. A pragmatic selection procedure:

  1. Benchmark bcrypt on your production hardware across a range of costs (for example, 10 through 15) using the exact library you will ship.
  2. Tabulate the per-hash latency for your peak concurrency (do not measure a single hash at idle — measure a synthetic burst).
  3. Pick the highest cost where the 99th-percentile login still completes within your SLO (typically 250 ms–1 s to hash).
  4. Re-run the benchmark annually or whenever you move to materially faster hardware, and raise the cost at the next natural migration.

Because the cost is stored inside each hash, raising it requires no database migration — as the verification deep-dive demonstrates, every future check simply runs at the stored cost. The hidden cost of staying on an old, low cost factor is far larger than the visible cost of raising it.

Reading a bcrypt hash string

A bcrypt hash is a self-describing string. Take the following hash, generated with the same library this tool uses, at cost 12 for the password correct horse battery staple:

$2b$12$25RkZGNmZqarn0GtfYjgN.2Lsl6aGloginW.W9dwFAq9PTZK0cXTq
  • $2b$ — version marker (see the previous section)
  • 12 — cost factor, meaning the key schedule runs 212 = 4,096 times
  • 25RkZGNmZqarn0GtfYjgN. — the 22-character Base64 encoding of the 16-byte salt
  • 2Lsl6aGloginW.W9dwFAq9PTZK0cXTq — the truncated 31-character Base64 key (the Blowfish output, chopped to fit the 60-character total)

Verify it yourself: paste the hash above into the verify tab with the password correct horse battery staple, and it should report a match. Because the hash embeds its own version, cost, and salt, any compliant bcrypt verifier — this page, Python's bcrypt.checkpw(), Ruby's BCrypt::Password#== — will accept it. The digest is only 184 bits: bcrypt was designed for password hashing, not for general-purpose integrity checks, so it keeps its output deliberately compact and slow to compute.

Where bcrypt wins in practice today

It is fair to ask why, in 2026, a new system would still pick a 1999 algorithm. The honest answer: bcrypt's weaknesses are architectural (no memory-hardness), and its strengths are operational (ubiquity, stability, and decades of production scrutiny). Consider your real constraints before ruling it out.

  • Library availability. bcrypt ships or is one install away in every mainstream language and framework — PHP's password_hash() defaults to it, Ruby's Rails has has_secure_password built on it, and Java/Go/Rust/Python all have mature bindings. Argon2 support is improving but is not yet uniform across every older stack you may be forced to interoperate with.
  • Legacy data. Existing bcrypt hash columns validate fine indefinitely; the cost factor is embedded, so you can raise it without migrating. A system that already stores bcrypt hashes is better served by raising the cost than by a risky in-place algorithm swap.
  • Known behavior. bcrypt has been analyzed for over two decades, and its properties are well documented. For a team without a dedicated cryptographer, choosing the algorithm with the longest successful deployment history is often the more defensible decision than adopting the newest one on a tight schedule.

The deciding factor is usually threat model and roadmap: if you are writing greenfield code on a modern stack and can afford the memory, Argon2id is the stronger choice; if you are maintaining a widely deployed system on a constrained stack, a properly costed bcrypt is still a solid, non-emergency posture.

Frequently asked questions

What is bcrypt?

bcrypt is a password-hashing function derived from the Blowfish cipher. It is deliberately slow and salted: every hash includes a random 128-bit salt, and the cost factor makes brute-force guessing progressively more expensive.

What cost factor should I use?

OWASP recommends a factor that takes more than 0.25 seconds on your hardware — commonly 10 to 12 in modern browsers. Higher factors are safer but slower for legitimate users, so tune it against real traffic.

Does the 72-byte limit matter?

Yes. bcrypt only processes the first 72 bytes of your input, so very long passwords are silently truncated. This page warns you when your password exceeds the limit.

Why can't I reverse a bcrypt hash?

bcrypt is one-way by construction. Combined with a unique salt, it defeats precomputed rainbow tables and forces an attacker to brute-force each password individually — which the cost factor makes impractically slow.

Is bcrypt still recommended over Argon2id?

Argon2id is the newer recommendation when your stack supports it. bcrypt remains a perfectly solid choice and is available in nearly every language, which is why it persists in production systems.

Other hash tools