Skip to content

Support 2b and 2y hashes. #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# JBCrypt
jBCrypt is an implementation the OpenBSD Blowfish password hashing algorithm,
as described in ["A Future-Adaptable Password
jBCrypt is an implementation of the OpenBSD Blowfish password hashing
algorithm, as described in ["A Future-Adaptable Password
Scheme"](http://www.openbsd.org/papers/bcrypt-paper.ps) by Niels Provos and
David Mazieres.

Expand Down
72 changes: 68 additions & 4 deletions src/main/java/org/mindrot/BCrypt.java
Original file line number Diff line number Diff line change
Expand Up @@ -661,8 +661,10 @@ public static String hashpw(String password, String salt) {
if (salt.charAt(2) == '$')
off = 3;
else {
if (salt.charAt(3) != '$')
throw new IllegalArgumentException ("Invalid salt revision");
minor = salt.charAt(2);
if (minor != 'a' || salt.charAt(3) != '$')
if (minor != 'a' && minor != 'b' && minor != 'y')
throw new IllegalArgumentException ("Invalid salt revision");
off = 4;
}
Expand All @@ -679,6 +681,27 @@ public static String hashpw(String password, String salt) {
throw new AssertionError("UTF-8 is not supported");
}

if (minor == 'b') {
/* Revision b fixed a bug in the OpenBSD
* implementation where passwords lengths
* larger than 256 bytes were unintionally
* wrapped due to integer overflow. It does
* this by capping the password length to 72
* characters (excluding the NUL-terminator,
* therefore 73).
*
* There should technically be no need to do
* so explicitly here since the encryption
* function only uses the first two 72 bytes
* anyway, but do it anyway for compatibility
* "just in case". */
if (passwordb.length > 73) {
byte[] trim = new byte[73];
System.arraycopy(passwordb, 0, trim, 0, 73);
passwordb = trim;
}
}

saltb = decode_base64(real_salt, BCRYPT_SALT_LEN);

B = new BCrypt();
Expand Down Expand Up @@ -708,16 +731,23 @@ public static String hashpw(String password, String salt) {
* @param log_rounds the log2 of the number of rounds of
* hashing to apply - the work factor therefore increases as
* 2**log_rounds.
* @param minor the minor revision of the algorithm to use;
* the latest revision is 'b'. Other accepted revisions are 'a'
* and 'y'.
* @param random an instance of SecureRandom to use
* @return an encoded salt value
*/
public static String gensalt(int log_rounds, SecureRandom random) {
public static String gensalt(int log_rounds, char minor, SecureRandom random) {
StringBuffer rs = new StringBuffer();
byte rnd[] = new byte[BCRYPT_SALT_LEN];

random.nextBytes(rnd);

rs.append("$2a$");
if (minor != 'a' && minor != 'b' && minor != 'y')
throw new IllegalArgumentException(
"unsupported minor revision: " + minor);

rs.append("$2" + minor + "$");
if (log_rounds < 10)
rs.append("0");
if (log_rounds > 30) {
Expand All @@ -730,6 +760,36 @@ public static String gensalt(int log_rounds, SecureRandom random) {
return rs.toString();
}

/**
* Generate a salt for use with the BCrypt.hashpw() method
* @param log_rounds the log2 of the number of rounds of
* hashing to apply - the work factor therefore increases as
* 2**log_rounds.
* @param random an instance of SecureRandom to use
* @return an encoded salt value
*/
public static String gensalt(int log_rounds, SecureRandom random) {
/* Support for b-hashes was added on Jan 22, 2020. The
* default revision of generated salts should arguably
* be cahgned to 'b' after some reasonable transition
* period. (A year?) */
return gensalt(log_rounds, 'a', random);
}

/**
* Generate a salt for use with the BCrypt.hashpw() method
* @param log_rounds the log2 of the number of rounds of
* hashing to apply - the work factor therefore increases as
* 2**log_rounds.
* @param minor the minor revision of the algorithm to use;
* the latest revision is 'b'. Other accepted revisions are 'a'
* and 'y'.
* @return an encoded salt value
*/
public static String gensalt(int log_rounds, char minor) {
return gensalt(log_rounds, minor, new SecureRandom());
}

/**
* Generate a salt for use with the BCrypt.hashpw() method
* @param log_rounds the log2 of the number of rounds of
Expand All @@ -738,7 +798,11 @@ public static String gensalt(int log_rounds, SecureRandom random) {
* @return an encoded salt value
*/
public static String gensalt(int log_rounds) {
return gensalt(log_rounds, new SecureRandom());
/* Support for b-hashes was added on Jan 22, 2020. The
* default revision of generated salts should arguably
* be cahgned to 'b' after some reasonable transition
* period. (A year?) */
return gensalt(log_rounds, 'a');
}

/**
Expand Down