Skip to content

Commit 2999faa

Browse files
committed
Update to jBCrypt 0.4 to correct an integer overflow (http://www.mindrot.org/projects/jBCrypt/news/rel04.html)
1 parent 1f9184a commit 2999faa

2 files changed

Lines changed: 38 additions & 10 deletions

File tree

‎ext/jruby/bcrypt_jruby/BCrypt.java‎

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
package bcrypt_jruby;
1616

1717
import java.io.UnsupportedEncodingException;
18-
1918
import java.security.SecureRandom;
2019

2120
/**
@@ -56,7 +55,7 @@
5655
* <p>
5756
* The amount of work increases exponentially (2**log_rounds), so
5857
* each increment is twice as much work. The default log_rounds is
59-
* 10, and the valid range is 4 to 31.
58+
* 10, and the valid range is 4 to 30.
6059
*
6160
* @author Damien Miller
6261
* @version 0.2
@@ -336,7 +335,9 @@ public class BCrypt {
336335
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
337336
};
338337

339-
// bcrypt IV: "OrpheanBeholderScryDoubt"
338+
// bcrypt IV: "OrpheanBeholderScryDoubt". The C implementation calls
339+
// this "ciphertext", but it is really plaintext or an IV. We keep
340+
// the name to make code comparison easier.
340341
static private final int bf_crypt_ciphertext[] = {
341342
0x4f727068, 0x65616e42, 0x65686f6c,
342343
0x64657253, 0x63727944, 0x6f756274
@@ -602,23 +603,24 @@ private void ekskey(byte data[], byte key[]) {
602603
* @param salt the binary salt to hash with the password
603604
* @param log_rounds the binary logarithm of the number
604605
* of rounds of hashing to apply
606+
* @param cdata the plaintext to encrypt
605607
* @return an array containing the binary hashed password
606608
*/
607-
private byte[] crypt_raw(byte password[], byte salt[], int log_rounds) {
609+
public byte[] crypt_raw(byte password[], byte salt[], int log_rounds,
610+
int cdata[]) {
608611
int rounds, i, j;
609-
int cdata[] = (int[])bf_crypt_ciphertext.clone();
610612
int clen = cdata.length;
611613
byte ret[];
612614

613-
if (log_rounds < 4 || log_rounds > 31)
615+
if (log_rounds < 4 || log_rounds > 30)
614616
throw new IllegalArgumentException ("Bad number of rounds");
615617
rounds = 1 << log_rounds;
616618
if (salt.length != BCRYPT_SALT_LEN)
617619
throw new IllegalArgumentException ("Bad salt length");
618620

619621
init_key();
620622
ekskey(salt, password);
621-
for (i = 0; i < rounds; i++) {
623+
for (i = 0; i != rounds; i++) {
622624
key(password);
623625
key(salt);
624626
}
@@ -679,14 +681,19 @@ public static String hashpw(String password, String salt) {
679681
saltb = decode_base64(real_salt, BCRYPT_SALT_LEN);
680682

681683
B = new BCrypt();
682-
hashed = B.crypt_raw(passwordb, saltb, rounds);
684+
hashed = B.crypt_raw(passwordb, saltb, rounds,
685+
(int[])bf_crypt_ciphertext.clone());
683686

684687
rs.append("$2");
685688
if (minor >= 'a')
686689
rs.append(minor);
687690
rs.append("$");
688691
if (rounds < 10)
689692
rs.append("0");
693+
if (rounds > 30) {
694+
throw new IllegalArgumentException(
695+
"rounds exceeds maximum (30)");
696+
}
690697
rs.append(Integer.toString(rounds));
691698
rs.append("$");
692699
rs.append(encode_base64(saltb, saltb.length));
@@ -712,6 +719,10 @@ public static String gensalt(int log_rounds, SecureRandom random) {
712719
rs.append("$2a$");
713720
if (log_rounds < 10)
714721
rs.append("0");
722+
if (log_rounds > 30) {
723+
throw new IllegalArgumentException(
724+
"log_rounds exceeds maximum (30)");
725+
}
715726
rs.append(Integer.toString(log_rounds));
716727
rs.append("$");
717728
rs.append(encode_base64(rnd, rnd.length));
@@ -747,6 +758,20 @@ public static String gensalt() {
747758
* @return true if the passwords match, false otherwise
748759
*/
749760
public static boolean checkpw(String plaintext, String hashed) {
750-
return (hashed.compareTo(hashpw(plaintext, hashed)) == 0);
761+
byte hashed_bytes[];
762+
byte try_bytes[];
763+
try {
764+
String try_pw = hashpw(plaintext, hashed);
765+
hashed_bytes = hashed.getBytes("UTF-8");
766+
try_bytes = try_pw.getBytes("UTF-8");
767+
} catch (UnsupportedEncodingException uee) {
768+
return false;
769+
}
770+
if (hashed_bytes.length != try_bytes.length)
771+
return false;
772+
byte ret = 0;
773+
for (int i = 0; i < try_bytes.length; i++)
774+
ret |= hashed_bytes[i] ^ try_bytes[i];
775+
return ret == 0;
751776
}
752777
}

‎spec/TestBCrypt.java‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1313
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1414

15+
package bcrypt_jruby;
16+
17+
import bcrypt_jruby.BCrypt;
1518
import junit.framework.TestCase;
1619

1720
/**
@@ -178,7 +181,7 @@ public void testCheckpw_failure() {
178181
*/
179182
public void testInternationalChars() {
180183
System.out.print("BCrypt.hashpw w/ international chars: ");
181-
String pw1 = "ππππππππ";
184+
String pw1 = "\u2605\u2605\u2605\u2605\u2605\u2605\u2605\u2605";
182185
String pw2 = "????????";
183186

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

0 commit comments

Comments
 (0)