Skip to content

Does this password match this hash?

Paste a bcrypt hash and the password you want to test. The comparison runs in this tab, the same way your login endpoint would run it, and nothing is sent anywhere.

Everything below this line runs locally

How verification actually works

There is no decryption step. bcrypt reads the version, cost and salt out of the stored string, hashes your candidate password with those exact settings, and compares the two digests. Same input plus same salt gives the same output, so a match proves the password without the hash ever having contained it.

That comparison should be constant time in real code, which is what every library's compare function gives you. Writing it yourself with a plain equality check leaks timing information about how much of the digest lined up.

$2b$12$R9h/cIPz0gi.URNNX3kh2O PST9/PgBkqquzi.Ss7KIUgO2t0jWMUW
└┬┘ └┬┘ └──────────┬─────────┘ └──────────────┬──────────────┘
 │   │             │                          │
 │   │             │                          the digest to compare against
 │   │             the salt, reused for your candidate
 │   the cost, so the work matches
 the version

The same check in your own code

Node.js

const ok = await bcrypt.compare(candidate, user.passwordHash);

PHP

if (password_verify($candidate, $user['password_hash'])) { }

Python

bcrypt.checkpw(candidate.encode(), stored_hash)

Go

err := bcrypt.CompareHashAndPassword(storedHash, []byte(candidate))

Spring Security

encoder.matches(candidate, storedHash)

Questions people ask

What do I need besides the hash?
Only the password you want to test. The version, cost and salt are all stored inside the hash string itself, which is why bcrypt needs a single database column and no separate settings.
Does the prefix have to match?
No. This page verifies $2a, $2b and $2y hashes, and so do most libraries. The prefix records which implementation wrote the hash rather than changing how it is checked.
It says no match but I am sure the password is right.
The usual causes are a trailing space or newline that came along with a copy and paste, a password longer than 72 bytes where the two sides truncated differently, or a hash that was stored in a column too narrow to hold all 60 characters.
Can I get the password out of the hash instead?
No, and no tool can. Bcrypt is a one way function. Verification works by hashing your candidate with the salt from the stored hash and comparing the result, which is why you have to supply a guess.
Is this the same check my application runs?
Yes. It calls compare from bcryptjs, which is the same operation as password_verify in PHP, checkpw in Python and matches in Spring Security.

Next