Skip to content

Commit e015c2c

Browse files
committed
Integer overflow fix (jBCrypt 0.4)
This corrects an integer overflow that occurs with very large log_rounds values, first reported by Marcus Rathsfeld.
1 parent 296f01f commit e015c2c

File tree

4 files changed

+39
-13
lines changed

4 files changed

+39
-13
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@ This is an alternative distribution of [jBCrypt](http://www.mindrot.org/projects
4242
packaged to ease use in existing applications — especially those using
4343
Apache Maven.
4444

45-
The code is unchanged from the original jBCrypt 0.3, however:
45+
The code is unchanged from the original jBCrypt 0.4, however:
4646

4747
- The classes have been moved to a java package to avoid pollution of the
4848
global namespace. *org.mindrot* was chosen to reflect their original origin.
49-
- The JBCrypt class javadoc has been changed to version 0.3. The official
49+
- The JBCrypt class javadoc has been changed to version 0.4. The official
5050
package incorrectly contains 0.2 as the stated version.
5151
- A pom.xml file has been added for use with Maven
5252

pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
<groupId>org.mindrot</groupId>
66
<artifactId>jbcrypt</artifactId>
7-
<version>0.3</version>
7+
<version>0.4</version>
88
<packaging>jar</packaging>
99

1010
<name>jbcrypt</name>

src/main/java/org/mindrot/BCrypt.java

+35-9
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,10 @@
5656
* <p>
5757
* The amount of work increases exponentially (2**log_rounds), so
5858
* each increment is twice as much work. The default log_rounds is
59-
* 10, and the valid range is 4 to 31.
59+
* 10, and the valid range is 4 to 30.
6060
*
6161
* @author Damien Miller
62-
* @version 0.3
62+
* @version 0.4
6363
*/
6464
public class BCrypt {
6565
// BCrypt parameters
@@ -336,7 +336,9 @@ public class BCrypt {
336336
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
337337
};
338338

339-
// bcrypt IV: "OrpheanBeholderScryDoubt"
339+
// bcrypt IV: "OrpheanBeholderScryDoubt". The C implementation calls
340+
// this "ciphertext", but it is really plaintext or an IV. We keep
341+
// the name to make code comparison easier.
340342
static private final int bf_crypt_ciphertext[] = {
341343
0x4f727068, 0x65616e42, 0x65686f6c,
342344
0x64657253, 0x63727944, 0x6f756274
@@ -602,23 +604,24 @@ private void ekskey(byte data[], byte key[]) {
602604
* @param salt the binary salt to hash with the password
603605
* @param log_rounds the binary logarithm of the number
604606
* of rounds of hashing to apply
607+
* @param cdata the plaintext to encrypt
605608
* @return an array containing the binary hashed password
606609
*/
607-
private byte[] crypt_raw(byte password[], byte salt[], int log_rounds) {
610+
public byte[] crypt_raw(byte password[], byte salt[], int log_rounds,
611+
int cdata[]) {
608612
int rounds, i, j;
609-
int cdata[] = (int[])bf_crypt_ciphertext.clone();
610613
int clen = cdata.length;
611614
byte ret[];
612615

613-
if (log_rounds < 4 || log_rounds > 31)
616+
if (log_rounds < 4 || log_rounds > 30)
614617
throw new IllegalArgumentException ("Bad number of rounds");
615618
rounds = 1 << log_rounds;
616619
if (salt.length != BCRYPT_SALT_LEN)
617620
throw new IllegalArgumentException ("Bad salt length");
618621

619622
init_key();
620623
ekskey(salt, password);
621-
for (i = 0; i < rounds; i++) {
624+
for (i = 0; i != rounds; i++) {
622625
key(password);
623626
key(salt);
624627
}
@@ -679,14 +682,19 @@ public static String hashpw(String password, String salt) {
679682
saltb = decode_base64(real_salt, BCRYPT_SALT_LEN);
680683

681684
B = new BCrypt();
682-
hashed = B.crypt_raw(passwordb, saltb, rounds);
685+
hashed = B.crypt_raw(passwordb, saltb, rounds,
686+
(int[])bf_crypt_ciphertext.clone());
683687

684688
rs.append("$2");
685689
if (minor >= 'a')
686690
rs.append(minor);
687691
rs.append("$");
688692
if (rounds < 10)
689693
rs.append("0");
694+
if (rounds > 30) {
695+
throw new IllegalArgumentException(
696+
"rounds exceeds maximum (30)");
697+
}
690698
rs.append(Integer.toString(rounds));
691699
rs.append("$");
692700
rs.append(encode_base64(saltb, saltb.length));
@@ -712,6 +720,10 @@ public static String gensalt(int log_rounds, SecureRandom random) {
712720
rs.append("$2a$");
713721
if (log_rounds < 10)
714722
rs.append("0");
723+
if (log_rounds > 30) {
724+
throw new IllegalArgumentException(
725+
"log_rounds exceeds maximum (30)");
726+
}
715727
rs.append(Integer.toString(log_rounds));
716728
rs.append("$");
717729
rs.append(encode_base64(rnd, rnd.length));
@@ -747,6 +759,20 @@ public static String gensalt() {
747759
* @return true if the passwords match, false otherwise
748760
*/
749761
public static boolean checkpw(String plaintext, String hashed) {
750-
return (hashed.compareTo(hashpw(plaintext, hashed)) == 0);
762+
byte hashed_bytes[];
763+
byte try_bytes[];
764+
try {
765+
String try_pw = hashpw(plaintext, hashed);
766+
hashed_bytes = hashed.getBytes("UTF-8");
767+
try_bytes = try_pw.getBytes("UTF-8");
768+
} catch (UnsupportedEncodingException uee) {
769+
return false;
770+
}
771+
if (hashed_bytes.length != try_bytes.length)
772+
return false;
773+
byte ret = 0;
774+
for (int i = 0; i < try_bytes.length; i++)
775+
ret |= hashed_bytes[i] ^ try_bytes[i];
776+
return ret == 0;
751777
}
752778
}

src/test/java/org/mindrot/TestBCrypt.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ public void testCheckpw_failure() {
180180
*/
181181
public void testInternationalChars() {
182182
System.out.print("BCrypt.hashpw w/ international chars: ");
183-
String pw1 = "ππππππππ";
183+
String pw1 = "\u2605\u2605\u2605\u2605\u2605\u2605\u2605\u2605";
184184
String pw2 = "????????";
185185

186186
String h1 = BCrypt.hashpw(pw1, BCrypt.gensalt());

0 commit comments

Comments
 (0)