From 9ff2ad64d3e164a0c6a01423d9686ad17938932a Mon Sep 17 00:00:00 2001 From: Fredrik Tolf Date: Wed, 22 Jan 2020 23:22:27 +0100 Subject: [PATCH 1/4] Support revision 2b hashes. --- src/main/java/org/mindrot/BCrypt.java | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/mindrot/BCrypt.java b/src/main/java/org/mindrot/BCrypt.java index 188193f..a47b876 100644 --- a/src/main/java/org/mindrot/BCrypt.java +++ b/src/main/java/org/mindrot/BCrypt.java @@ -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') throw new IllegalArgumentException ("Invalid salt revision"); off = 4; } @@ -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(); From 98789e4e4318758131dcd7d4651f0f33583d6c5a Mon Sep 17 00:00:00 2001 From: Fredrik Tolf Date: Wed, 22 Jan 2020 23:24:18 +0100 Subject: [PATCH 2/4] Fixed README typo. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dfa6428..2107fdc 100644 --- a/README.md +++ b/README.md @@ -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. From 57cd5eaa5457b66a8b12fd7b9fcfe6cb2afc3de7 Mon Sep 17 00:00:00 2001 From: Fredrik Tolf Date: Wed, 22 Jan 2020 23:37:05 +0100 Subject: [PATCH 3/4] Add support for 2y hases as well. They should be identical to 2b. It's really unclear to me why the php-bcrypt authors decided to use 2y instead. --- src/main/java/org/mindrot/BCrypt.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/mindrot/BCrypt.java b/src/main/java/org/mindrot/BCrypt.java index a47b876..7fe73b0 100644 --- a/src/main/java/org/mindrot/BCrypt.java +++ b/src/main/java/org/mindrot/BCrypt.java @@ -664,7 +664,7 @@ public static String hashpw(String password, String salt) { if (salt.charAt(3) != '$') throw new IllegalArgumentException ("Invalid salt revision"); minor = salt.charAt(2); - if (minor < 'a' || minor > 'b') + if (minor != 'a' && minor != 'b' && minor != 'y') throw new IllegalArgumentException ("Invalid salt revision"); off = 4; } From ec5fe934fb16105c60adc6881b71cb3d53c5b476 Mon Sep 17 00:00:00 2001 From: Fredrik Tolf Date: Wed, 22 Jan 2020 23:57:44 +0100 Subject: [PATCH 4/4] Added gensalt functions that take an explicitly specified hash revision. --- src/main/java/org/mindrot/BCrypt.java | 47 +++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/mindrot/BCrypt.java b/src/main/java/org/mindrot/BCrypt.java index 7fe73b0..1a23a36 100644 --- a/src/main/java/org/mindrot/BCrypt.java +++ b/src/main/java/org/mindrot/BCrypt.java @@ -731,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) { @@ -753,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 @@ -761,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'); } /**