Where 2x prefix are used in BCrypt?

msoa picture msoa ยท Mar 31, 2013 ยท Viewed 12.8k times ยท Source

The question is the same title, Where $2x$ is used in BCrypt?

The following scenario is right?

We have a set of passwords that hashed with $2a$ prefix already, when the Server PHP version was earlier 5.3.7. Now we upgraded the PHP to 5.3.7+, now we must firstly verify previous passwords with $2x$ algorithm then rehash the password with $2y$ prefix. That's right?

Answer

Ian Boyd picture Ian Boyd ยท Mar 25, 2016

Note to wikipedia editors: Content in this answer is in the public domain; i know because i wrote it. I wrote it first for myself, and later put it on Stackoverflow. I also know it because everything on Stackoverflow is copyleft. And even if it wasn't, anyone is free to use it anywhere, at any time, for any reason, by anyone. How do i know? Because i wrote it and i just said so. That includes the Bcrypt entry on Wikipedia. In Wikipedia parlance: I donate it.

So stop claiming copyright violations when you don't know what you're talking about.

BCrypt variants

$2$

BCrypt was designed by the OpenBSD people. It was designed to hash passwords for storage in the OpenBSD password file. Hashed passwords are stored with a prefix to identify the algorithm used. BCrypt got the prefix $2$.

This was in contrast to the other algorithm prefixes:

  • $1$: MD5
  • $5$: SHA-256
  • $6$: SHA-512

$2a$

The original BCrypt specification did not define how to handle non-ASCII characters, or how to handle a null terminator. The specification was revised to specify that when hashing strings:

  • the string must be UTF-8 encoded
  • the null terminator must be included

$2x$, $2y$ (June 2011)

A bug was discovered in crypt_blowfish๐Ÿ•—, a PHP implementation of BCrypt. It was mis-handling characters with the 8th bit set.

They suggested that system administrators update their existing password database, replacing $2a$ with $2x$, to indicate that those hashes are bad (and need to use the old broken algorithm). They also suggested the idea of having crypt_blowfish emit $2y$ for hashes generated by the fixed algorithm. Nobody else, including canonical OpenBSD, adopted the idea of 2x/2y. This version marker was was limited to crypt_blowfish๐Ÿ•—.

The versions $2x$ and $2y$ are not "better" or "stronger" than $2a$. They are remnants of one particular buggy implementation of BCrypt.

$2b$ (February 2014)

A bug was discovered in the OpenBSD implementation of BCrypt. They were storing the length of their strings in an unsigned char. If a password was longer than 255 characters, it would overflow and wrap at 255.

BCrypt was created for OpenBSD. When they have a bug in their library, they decided its ok to bump the version. This means that everyone else needs to follow suit if you want to remain current to "their" specification.

The version $2b$ is not "better" or "stronger" than $2a$. It is a remnant of one particular buggy implementation of BCrypt. But since BCrypt canonically belongs to OpenBSD, they get to change the version marker to whatever they want.

There is no difference between 2a, 2x, 2y, and 2b. If you wrote your implementation correctly, they all output the same result.

And if you were doing the right thing from the beginning (storing strings in utf8 and also hashing the null terminator) then: there is no difference between 2, 2a, 2x, 2y, and 2b. If you wrote your implementation correctly, they all output the same result.

The only people who need to care about 2x and 2y are those you may have been using crypt_blowfish. And the only people who need to care about 2b are those who may have been running OpenBSD.

All other correct implementations are identical and correct.