DevToolsmith

Bcrypt Hash Generator and Verifier

Hash a password with bcrypt at any cost factor, or check whether a password matches an existing $2a$, $2b$ or $2y$ hash. The tool also breaks a hash down into its version, cost, salt and checksum, and warns about the 72-byte limit.

Runs 100% in your browser — nothing is uploaded

Anatomy of a bcrypt hash

A bcrypt hash is always 60 characters
$2b$12$R9h/cIPz0gi.URNNX3kh2OPST9/PgBkqquzi.Ss7KIUgO2t0jWMUW
 \/ \/ \____________________/\_____________________________/
 |  |          |                          |
 |  cost       salt (22 chars)            hash (31 chars)
 version
  • Version (2b): which revision of the algorithm made the hash.
  • Cost (12): the work factor. bcrypt runs 2^cost rounds of its key setup, so cost 12 means 4,096 rounds.
  • Salt: 16 random bytes in bcrypt’s own Base64 alphabet (./A–Za–z0–9), unique per hash.
  • Hash: the 23-byte result. Everything needed to verify a password is in the string, so you store it in a single column (CHAR(60)).

Using bcrypt in your code

Node.js (bcrypt or bcryptjs)
import bcrypt from 'bcrypt';

const hash = await bcrypt.hash(password, 12);
const ok = await bcrypt.compare(password, hash);  // true or false
Python (bcrypt)
import bcrypt

hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))
ok = bcrypt.checkpw(password.encode(), hashed)
PHP
$hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
$ok = password_verify($password, $hash);

if (password_needs_rehash($hash, PASSWORD_BCRYPT, ['cost' => 12])) {
    // store password_hash($password, ...) again
}
Go (golang.org/x/crypto/bcrypt)
hash, err := bcrypt.GenerateFromPassword([]byte(password), 12)
err = bcrypt.CompareHashAndPassword(hash, []byte(password)) // nil if it matches
htpasswd (Apache, nginx basic auth)
htpasswd -nbBC 12 alice 'secret'   # prints alice:$2y$12$...

The hashing here runs in your browser with bcrypt.js, so passwords are never sent anywhere. Need a strong password to hash? Use the password generator. Looking for MD5 or SHA-256 instead? Those are in the hash generator.

Frequently asked questions

What cost factor should I use for bcrypt?

Pick the highest cost that keeps hashing around 250 ms on your production server. In 2026 that is usually 12 (OWASP recommends at least 10). Each step doubles the time: cost 13 takes twice as long as 12. Re-check every few years, and rehash on login when a user’s stored hash has a lower cost than your current setting.

Why does the same password give a different hash every time?

Each hash includes a new random 16-byte salt, stored in characters 8 to 29 of the hash. Two users with the same password get different hashes, so attackers can’t use precomputed tables. To check a password, don’t hash it again and compare strings. Use your library’s compare or verify function, which reads the salt and cost from the stored hash.

What is the difference between $2a$, $2b$ and $2y$?

They mark revisions of the algorithm. $2a$ is the classic version. $2b$ (2014) fixes a bug in OpenBSD’s implementation with passwords longer than 255 bytes. $2y$ is PHP’s marker for its corrected implementation and is equivalent to $2b$. For normal passwords all three produce the same result, and this tool verifies all of them.

Is there a maximum password length?

Yes. bcrypt only uses the first 72 bytes of the password; the rest is ignored. With UTF-8, that can be fewer than 72 characters (an emoji is 4 bytes). The tool warns when a password is longer. If you need to support longer passwords, the safe approach is to pre-hash with HMAC-SHA256 and Base64-encode the result before bcrypt, or use Argon2id instead.

bcrypt or Argon2?

Both are fine for password storage. OWASP lists Argon2id first because it is memory-hard, which makes GPU attacks more expensive, and it has no 72-byte limit. bcrypt is older, available in every language and framework, and still a solid choice at cost 10 or higher. Avoid MD5, SHA-1 and plain SHA-256 for passwords; they are designed to be fast.