About bcrypt Hash Generator
bcrypt is a password hashing function, which is a different thing from a general-purpose hash. It is deliberately slow, it salts every password automatically, and its cost is tunable - three properties that make it suitable for storing passwords and that SHA-256, for all its cryptographic strength, entirely lacks.
The cost factor is a base-2 logarithm, so each increment doubles the work. Cost 10 is roughly 1,024 iterations of the underlying key setup, cost 12 is four times that. The usual guidance is to pick the highest cost your login path can tolerate - around 250ms is a common target - which in 2026 means cost 12 to 14 on typical server hardware. Because it is logarithmic, raising the cost by two is a fourfold increase, not a small tweak.
A bcrypt hash carries everything needed to verify it, which is why you store the string as-is and never a separate salt column. In $2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewKyPS.HFOo0Zx3e, $2b$ is the algorithm version, 12 is the cost, and the remaining 53 characters are the 22-character Base64 salt followed by the 31-character digest. Verification reads the cost and salt back out of the stored string.
The one genuine limitation is the 72-byte input cap: bcrypt silently ignores everything past 72 bytes, so two long passwords sharing a 72-byte prefix are interchangeable. It matters less than it sounds for human passwords, but it becomes a real problem if you pre-hash to hex (doubling the length) or accept passphrases. If you need unbounded input, Argon2id handles it and is the better default for new systems anyway.
Hashing here runs in your browser, and the cost factor means a high setting will take a visible moment - which is the point of the algorithm working.
How to use the bcrypt Hash Generator
- Enter the password and choose a cost factor - 12 is a reasonable default for testing.
- Generate. A fresh random salt is used every time, so the same password produces a different hash on each run.
- Store the whole $2b$... string in one column; it already contains the version, cost and salt.
- To check a password, use your library's compare function - never hash again and compare strings, because the salt differs.
bcrypt Hash Generator in code
The same operation this tool performs, in the languages you are most likely to need it.
import bcrypt from "bcrypt";
const COST = 12; // raise until login takes ~250ms on your hardware
// Registration - salt is generated and embedded automatically
const hash = await bcrypt.hash(password, COST);
// "$2b$12$..." - store this single string, no separate salt column
// Login - compare, never re-hash and string-compare
const ok = await bcrypt.compare(password, storedHash);
// Transparent cost upgrade on successful login
if (ok && bcrypt.getRounds(storedHash) < COST) {
await users.update(id, { hash: await bcrypt.hash(password, COST) });
}
// The 72-byte cap is silent - reject over-long input explicitly
if (Buffer.byteLength(password, "utf8") > 72) {
throw new Error("Password too long");
}
import bcrypt
# bcrypt wants bytes, and gensalt embeds the cost
hashed = bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt(rounds=12))
# Verify
bcrypt.checkpw(password.encode("utf-8"), hashed)
# Or let passlib handle cost upgrades and algorithm migration
from passlib.context import CryptContext
pwd = CryptContext(schemes=["argon2", "bcrypt"], deprecated="auto")
h = pwd.hash(password) # uses argon2, the first scheme
if pwd.verify(password, stored): # verifies either scheme
if pwd.needs_update(stored):
stored = pwd.hash(password) # migrate transparently on login
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
var encoder = new BCryptPasswordEncoder(12);
String hash = encoder.encode(rawPassword);
boolean ok = encoder.matches(rawPassword, hash);
// For new systems, prefer Argon2 and let DelegatingPasswordEncoder
// handle migration from existing bcrypt hashes:
// PasswordEncoderFactories.createDelegatingPasswordEncoder()
// Stored hashes are prefixed {bcrypt} / {argon2} so both verify.
-- One column, 60 characters. No separate salt column.
CREATE TABLE users (
id uuid PRIMARY KEY,
email text NOT NULL UNIQUE,
password_hash char(60) NOT NULL, -- "$2b$12$..." is always 60 chars
created_at timestamptz NOT NULL DEFAULT now()
);
-- Use varchar(255) instead if you may migrate to Argon2, whose
-- encoded form is longer and variable.
-- Never do the hashing in SQL: the plaintext ends up in query logs,
-- and the database is the wrong place to spend that CPU.
When you need this
- Generating a test hash to seed a development database with a known password.
- Checking what cost factor an existing hash was created with.
- Confirming a password verifies against a stored hash while debugging a login failure.
- Measuring how long a given cost factor takes before choosing one.
- Producing a fixture hash for an integration test.
Common problems and what causes them
- Hashing again and comparing strings
- Every hash uses a fresh random salt, so hashing the same password twice gives different strings. Always use the library's compare/checkpw/matches function, which reads the salt out of the stored hash.
- The silent 72-byte truncation
- bcrypt ignores input past 72 bytes without warning, so two long passwords sharing a 72-byte prefix are equivalent. This gets worse if you pre-hash to hex first, which doubles the length. Reject over-long input explicitly, or use Argon2id.
- Storing a separate salt column
- The salt is already inside the hash string, between the cost and the digest. A separate column is redundant and invites a mismatch. Store the 60-character string and nothing else.
- Cost factor too low
- Cost 8 was reasonable a decade ago and is fast enough to brute-force now. Because cost is logarithmic, moving from 10 to 12 is a fourfold increase in work. Target roughly 250ms on your production hardware and re-evaluate periodically.
- Using SHA-256 for passwords instead
- A fast hash is exactly wrong here: commodity GPUs compute billions of SHA-256 hashes per second, so a leaked table falls quickly. bcrypt, scrypt and Argon2 are slow and memory-hard by design.
- Ignoring the $2a$ / $2b$ / $2y$ version prefixes
- These mark revisions that fixed a sign-extension bug and an unsigned-char handling difference. Most libraries verify all of them, but generate $2b$. A hash that fails to verify across two languages is sometimes a version-handling difference.
- Hashing in the database or in the client
- Hashing in SQL puts plaintext in query logs. Hashing in the client makes the hash the effective password, so a stolen hash is a working credential. Hash on the server, over TLS.
FAQ
- What cost factor should I use for bcrypt?
- The highest your login path tolerates - around 250ms is a common target, which means roughly 12 to 14 on typical 2026 server hardware. Cost is a base-2 exponent, so each increment doubles the work and going from 10 to 12 quadruples it. Benchmark on the hardware you actually deploy to.
- Why does the same password produce a different hash each time?
- Because a fresh random salt is generated per hash and embedded in the output. That is what stops identical passwords producing identical hashes and makes precomputed rainbow tables useless. Verify with the compare function, never by re-hashing.
- Do I need a separate salt column?
- No. The salt is stored inside the hash string - characters 8 to 29 of the $2b$... value. Store the single 60-character string; the verify function extracts the cost and salt itself.
- bcrypt or Argon2 - which should I choose?
- Argon2id for new systems: it is memory-hard, which resists GPU and ASIC attacks better, it has no input length limit, and it won the Password Hashing Competition. bcrypt remains perfectly acceptable and is extremely well tested - there is no urgency to migrate existing hashes, and you can upgrade them transparently on next login.
- What is the 72-byte limit?
- bcrypt only processes the first 72 bytes of input and discards the rest silently, so two long passwords sharing a 72-byte prefix verify against each other. Reject longer input explicitly, and be careful about pre-hashing schemes that inflate the length.
- Can I use bcrypt for API keys or tokens?
- You can, but you usually should not need to. bcrypt's slowness exists to frustrate guessing of low-entropy human passwords. A randomly generated 256-bit token is not guessable, so a single fast SHA-256 is sufficient and far cheaper on a hot path.
- Production passwords?
- Use your app's auth library; this is for quick test hashes.