How bcrypt resists GPUs
Why bcrypt drops cracking throughput from billions to thousands per second: the cost factor, its GPU-hostile key schedule, and the 72-byte truncation gotcha.
bcrypt is the boring, correct answer to password storage, and the reason it is correct is the same reason attackers hate it: it refuses to go fast.
Where MD5 hands a GPU tens of billions of guesses per second, a well-tuned bcrypt hash drops that to a few thousand. That is not a tuning artifact. It is the entire design, and it holds up against the hardware that makes fast hashes worthless.
The cost factor is the dial
A bcrypt hash carries its own parameters. A string like $2y$12$R9h... decodes as algorithm 2y, cost 12, then a 22-character base64 salt and the digest. That 12 is the work factor, and it is a base-2 exponent: the key schedule runs 2^12 = 4096 iterations. Bump it to 13 and you double the work. Drop to 10 and you quarter it.
This is what lets bcrypt age gracefully. You pick a cost today, and in three years when hardware is faster you raise it by one or two and stay ahead. The hash format records the cost it was created with, so old and new hashes coexist and you can upgrade each one at the user's next login.
Why Blowfish hates GPUs
The slowness is not just iteration count. MD5 iterated 4096 times would still crack faster than bcrypt, because the iterations are not the whole story.
bcrypt is built on a modified Blowfish key schedule called EksBlowfish. Blowfish encryption depends on large S-boxes, four tables of 256 32-bit entries, that are constantly read and rewritten during key setup. Every round does small, data-dependent memory lookups into state that does not fit neatly into a GPU's fast registers or shared memory. GPUs win when thousands of threads run the same instruction over wide, predictable data. bcrypt gives them the opposite: scattered, serial-ish memory access per guess, with each thread fighting for the same scarce on-chip memory.
The result is that a GPU's thousands of cores cannot all stay busy. Per-core, bcrypt is roughly as slow on a GPU as on a CPU, which erases the attacker's usual 1000x hardware edge. This is the deliberate contrast with the danger of fast hashes: bcrypt is engineered to be hostile to exactly the parallelism that makes MD5 and NTLM fall in seconds.
Cracking bcrypt in practice
You attack bcrypt with hashcat mode -m 3200.
hashcat -m 3200 -a 0 hashes.txt small-targeted.txt -r rules/best64.rule
Notice the wordlist. Against MD5 you throw rockyou and a fat ruleset because you can afford a hundred million candidates. Against bcrypt at cost 12 you cannot. At a few thousand guesses per second, rockyou alone is a multi-week run before rules even enter the picture. So you bring tiny, high-signal lists: company name variants, breach-correlated passwords for the specific users, OSINT-derived patterns. You spend your guesses where they are most likely to land. This is the discipline behind wordlists and rules that actually work, and bcrypt is where ignoring it costs you the engagement.
If the passwords were genuinely strong and the cost is reasonable, you do not crack bcrypt. You move on and find another way in. That is the honest outcome, and it is the point.
The 72-byte truncation gotcha
bcrypt only processes the first 72 bytes of the password. Everything past that is silently ignored. A 200-character passphrase is, to bcrypt, just its first 72 bytes. This usually does not matter, but it bites when an application pre-pads input or concatenates fields.
Worse is the null-byte problem. Some bcrypt implementations are backed by C string handling and truncate at the first \0. Feed in a password containing a null byte and everything after it vanishes, occasionally collapsing security to almost nothing.
Both issues converge on a single bad pattern: pre-hashing. Teams who want to support long passwords sometimes run SHA-256 first, then bcrypt the digest. Reasonable in principle, but if you base64 or hex the digest you are fine, while if you pass the raw 32 binary bytes you can hit an embedded null and truncate. The safe recipe is to pre-hash with SHA-256, base64-encode the result, then bcrypt that. Know which one your stack does.
What defenders should actually do
Pick a cost factor by measurement, not by folklore. Target roughly 250 milliseconds per verification on your production hardware. That is slow enough to crush an attacker and fast enough that users never notice at login. On current servers that tends to land around cost 12 to 14, but measure it yourself, because a number copied from a 2015 blog post may now be trivially fast.
Then treat the cost as something you revisit. Schedule a review, rehash on login when you raise it, and watch your auth latency so a cost bump does not quietly become a denial-of-service vector. bcrypt does not need replacing for most systems. It needs you to keep turning the dial.