Bcrypt Generator & Checker

Generate and check bcrypt hashes in your browser. Pick $2b$, $2y$ or $2a$, see the 72-byte limit and which of PHP, Laravel, Node.js, Go or Spring accept it.

  • Runs in your browser
  • Your data never leaves your browser
  • Free · No Sign-Up
Choose the prefix accepted by the program that will check the hash. Use $2y$ for PHP and Laravel, or $2b$ for Node.js bcrypt. The note explains the selected prefix’s compatibility.
Choose a cost from 4 to 31; the default is 12. Each increase doubles the work. The estimate uses the measured speed of this browser; measure again on your login server.
Generate hash starts a new calculation with a random 16-byte salt. The result separates the prefix, cost, 22-character salt and 31-character hash. Cancel stops the current calculation.

The count uses UTF-8 bytes. bcrypt reads only the first 72 bytes; spaces and line breaks count, and Unicode is not normalized. Longer passwords produce a warning.

Hashing runs in a Web Worker in this tab. Passwords and hashes are not sent anywhere or saved, and this page loads no analytics or ads.

Examples, details and FAQ Worked examples, how it compares with other tools, and answers to common questions.

Examples

A Spring Security value. The Spring Security reference (Password Storage) stores the password password like this. The Example button fills it in:

{bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG

The page strips the {bcrypt} id that DelegatingPasswordEncoder adds and reports a match.

A PHP hash for a Node.js service. PHP 8.4 password_hash(“correct horse battery staple”, PASSWORD_BCRYPT) returned this on 2026-10-02:

$2y$12$wz5da1i8Rk.FgE0MhaU3Jev51XAHhPzMRebBW4kXVqBbDO8acchn2

In the same test, bcrypt.compareSync() from the Node.js bcrypt package 6.0.0 returned false for every $2y$ hash. The Check tab shows the hash with a $2b$ prefix, $2b$12$wz5da1i8Rk.FgE0MhaU3Jev51XAHhPzMRebBW4kXVqBbDO8acchn2, which that package accepts.

A Docker Compose label. Compose reads $ as the start of a variable, so a literal dollar sign is written $$ (Compose interpolation). A basic-auth user list copied from such a file looks like this:

admin:$$2y$$12$$SVhOQ29BkxG9DYgTkPXqMuE4ZzjTo93.uW11Jps7hP09jZzVT7LZq

The page takes the part after admin: and turns $$ back into $.

A damaged hash. A hash missing its last character is reported as 59 of 60 characters, and a character outside the bcrypt alphabet by its position, here character 41:

$2b$05$.vOjLibWYVoJlI08x8Bv.em8Qy7cOWg3j!TZvJxhB4iON3pFKvtu.

Which prefix: $2a$, $2b$ or $2y$

All three run the same algorithm on UTF-8 passwords. The labels mark bug fixes: $2y$ marks hashes from crypt_blowfish after the 8-bit bug CVE-2011-2483 was fixed, and $2b$ marks OpenBSD hashes after a 2014 password-length fix; crypt_blowfish 1.3 treats $2b$ “exactly the same” as $2y$ (Openwall crypt_blowfish). What matters today is which label a library accepts; we ran the same hashes through each on 2026-10-02:

LibraryVersion$2a$$2b$$2y$Hashing over 72 bytesWrites
PHP password_verify 8.4.26✓✓✓✂ cuts$2y$12$
Laravel Hash::check 13.34.0⚠ throws⚠ throws✓✂ cuts$2y$12$
Symfony NativePasswordHasher 8.1.0✓✓✓SHA-512 first$2y$13$
Python bcrypt 5.0.0✓✓✓✗ error$2b$12$
Python bcrypt 4.2.0✓✓✓✂ cuts$2b$12$
Node.js bcrypt 6.0.0✓✓✗ false✂ cuts$2b$10$
Node.js bcryptjs 3.0.3✓✓✓✂ cuts$2b$10$
Go x/crypto/bcrypt 0.57.0✓✓✓✗ error$2a$10$
Spring Security 7.1.1✓✓✓✗ error$2a$10$
Spring Security 6.5.11✓✓✓✗ error$2a$10$

“✓” means the right password matched. Laravel throws RuntimeException: This password does not use the Bcrypt algorithm. because its framework config sets HASH_VERIFY to true and PHP’s password_get_info() only names $2y$ hashes “bcrypt” (Laravel docs). So write $2y$ for PHP, $2b$ for Node.js, and any of the three for Python, Go or Java. Changing only the prefix keeps a hash valid, which the Check tab does for you.

The 72-byte limit

bcrypt reads at most 72 bytes of the password. Bytes, not characters, count: an ASCII letter is one byte, most Chinese, Japanese and Korean characters three. A 24-character Chinese password already fills the limit. The libraries above split three ways: PHP, Node.js and bcryptjs cut silently, Python bcrypt 5, Go and Spring Security 6.3 or later refuse to hash, and Symfony hashes longer passwords with SHA-512 first. This sentence-long password shows the warning:

my dog's name is Biscuit and he was born in Portland, Oregon in the spring of 2019

It is 82 bytes, so everything after “… in the spri” has no effect, and “…spring of 2020” checks as a match too. A NUL character is another trap: PHP’s password_hash() refuses it and password_verify() stops reading at it, while this page, Python, Node.js, Go and Spring include it.

Choosing the cost

Cost is a base-2 exponent: cost 12 runs 212 = 4,096 rounds of key setup, twice the work of cost 11. OWASP asks for “a minimum of 10”. Defaults differ: PHP raised password_hash() from 10 to 12 in 8.4 (RFC), Laravel and Python use 12, Node.js bcrypt, Go and Spring use 10. The estimate here is for a JavaScript bcrypt in this browser; time the cost on the server that will check logins.

When bcrypt is the wrong choice

The OWASP Password Storage Cheat Sheet recommends Argon2id (19 MiB of memory, 2 iterations), then scrypt, and says bcrypt “should only be used for password storage in legacy systems where Argon2 and scrypt are not available”. If you need passwords over 72 bytes with bcrypt, it describes bcrypt(base64(hmac-sha384(password, pepper))) and calls plain bcrypt(base64(sha512(password))) “a dangerous practice”, because a leaked SHA-512 hash can then be tested directly. For API tokens a keyed HMAC is the usual tool, and checksums belong in the hash generator.

How this page compares

We gave the same inputs to tools that rank for “bcrypt generator” on Bing on 2026-10-02. bcrypt-generator.com, xyutil.com and 33tool.com hash in the browser but write only $2a$, and all three reported a match for a 73-byte password against the hash of its first 72 bytes without a warning. A hash with a ! in it was “does not match” on bcrypt-generator.com and xyutil.com instead of a format error. MiniWebtool’s Japanese page posted the password in a form to its server (password=correct horse battery staple in the request). This page keeps the password in the tab, lets you choose the prefix, and explains a mismatch.

Limits

  • The page uses bcryptjs 2.4.3. A cost of 31 is accepted but would take days in a browser; cancel a long run with Cancel.
  • $2x$ hashes, made by the old crypt_blowfish bug, are checked as $2a$ when the password is all ASCII; for other passwords the page says it cannot reproduce the bug.
  • Passwords are hashed as UTF-8 without Unicode normalization, so the same text typed with another input method may differ in bytes.
  • Only bcrypt is supported. Argon2, scrypt, SHA-crypt and phpass hashes are recognized and named, not checked. For Apache and Nginx files use the htpasswd generator; for a random password use the password generator.

FAQ

Which prefix should I choose: $2a$, $2b$ or $2y$?

Pick the one your verifying library writes itself. For PHP, Laravel and Symfony use $2y$; Laravel's Hash::check() throws for $2a$ and $2b$ unless HASH_VERIFY=false. For Node.js use $2b$, because the bcrypt package 6.0.0 returns false for $2y$. Python bcrypt, Go and Spring Security accept all three.

Can I change $2y$ to $2b$ in a stored hash?

Yes, for UTF-8 passwords shorter than 256 bytes. The three prefixes run the same algorithm, so only the label changes. The Check tab lists the other two forms of any valid hash with a copy button.

Why does my correct password not match?

Common causes are a hash cut off when it was copied (a bcrypt hash is 60 characters), $$ left in from a Docker Compose file, a $2y$ hash checked by Node.js bcrypt, a password that differs after its first 72 bytes being treated as the same, and padding bits in the last character that some tools set. The Check tab reports each of these.

What cost should I use?

OWASP asks for at least 10. PHP 8.4, Laravel and Python bcrypt default to 12; Node.js bcrypt, Go and Spring Security default to 10. Pick the highest cost your login server can compute in well under a second, and measure it on that server.

Is my password sent anywhere?

No. Hashing runs in a Web Worker in your browser tab. The page sends no request with the password or the hash, saves nothing, and does not load analytics or ads.