Skip to content

Commit 0bd7daf

Browse files
jzheauxrwinch
authored andcommitted
Improve Upgrading
1 parent c6461d6 commit 0bd7daf

File tree

3 files changed

+55
-13
lines changed

3 files changed

+55
-13
lines changed

crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCrypt.java

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -526,35 +526,47 @@ static long roundsForLogRounds(int log_rounds) {
526526
* @param safety bit 16 is set when the safety measure is requested
527527
* @return an array containing the binary hashed password
528528
*/
529-
private byte[] crypt_raw(byte password[], byte salt[], int log_rounds, boolean sign_ext_bug, int safety) {
530-
int rounds, i, j;
529+
private byte[] crypt_raw(byte password[], byte salt[], int log_rounds, boolean sign_ext_bug, int safety,
530+
boolean for_check) {
531531
int cdata[] = bf_crypt_ciphertext.clone();
532532
int clen = cdata.length;
533-
byte ret[];
534533

534+
long rounds;
535535
if (log_rounds < 4 || log_rounds > 31) {
536-
throw new IllegalArgumentException("Bad number of rounds");
536+
if (!for_check) {
537+
throw new IllegalArgumentException("Bad number of rounds");
538+
}
539+
if (log_rounds != 0) {
540+
throw new IllegalArgumentException("Bad number of rounds");
541+
}
542+
rounds = 0;
543+
}
544+
else {
545+
rounds = roundsForLogRounds(log_rounds);
546+
if (rounds < 16 || rounds > Integer.MAX_VALUE) {
547+
throw new IllegalArgumentException("Bad number of rounds");
548+
}
537549
}
538-
rounds = 1 << log_rounds;
550+
539551
if (salt.length != BCRYPT_SALT_LEN) {
540552
throw new IllegalArgumentException("Bad salt length");
541553
}
542554

543555
init_key();
544556
ekskey(salt, password, sign_ext_bug, safety);
545-
for (i = 0; i < rounds; i++) {
557+
for (int i = 0; i < rounds; i++) {
546558
key(password, sign_ext_bug, safety);
547559
key(salt, false, safety);
548560
}
549561

550-
for (i = 0; i < 64; i++) {
551-
for (j = 0; j < (clen >> 1); j++) {
562+
for (int i = 0; i < 64; i++) {
563+
for (int j = 0; j < (clen >> 1); j++) {
552564
encipher(cdata, j << 1);
553565
}
554566
}
555567

556-
ret = new byte[clen * 4];
557-
for (i = 0, j = 0; i < clen; i++) {
568+
byte[] ret = new byte[clen * 4];
569+
for (int i = 0, j = 0; i < clen; i++) {
558570
ret[j++] = (byte) ((cdata[i] >> 24) & 0xff);
559571
ret[j++] = (byte) ((cdata[i] >> 16) & 0xff);
560572
ret[j++] = (byte) ((cdata[i] >> 8) & 0xff);
@@ -563,6 +575,10 @@ private byte[] crypt_raw(byte password[], byte salt[], int log_rounds, boolean s
563575
return ret;
564576
}
565577

578+
private static String hashpwforcheck(byte[] passwordb, String salt) {
579+
return hashpw(passwordb, salt, true);
580+
}
581+
566582
/**
567583
* Hash a password using the OpenBSD bcrypt scheme
568584
* @param password the password to hash
@@ -584,6 +600,10 @@ public static String hashpw(String password, String salt) {
584600
* @return the hashed password
585601
*/
586602
public static String hashpw(byte passwordb[], String salt) {
603+
return hashpw(passwordb, salt, false);
604+
}
605+
606+
private static String hashpw(byte passwordb[], String salt, boolean for_check) {
587607
BCrypt B;
588608
String real_salt;
589609
byte saltb[], hashed[];
@@ -633,7 +653,7 @@ public static String hashpw(byte passwordb[], String salt) {
633653
}
634654

635655
B = new BCrypt();
636-
hashed = B.crypt_raw(passwordb, saltb, rounds, minor == 'x', minor == 'a' ? 0x10000 : 0);
656+
hashed = B.crypt_raw(passwordb, saltb, rounds, minor == 'x', minor == 'a' ? 0x10000 : 0, for_check);
637657

638658
rs.append("$2");
639659
if (minor >= 'a') {
@@ -740,7 +760,8 @@ public static String gensalt() {
740760
* @return true if the passwords match, false otherwise
741761
*/
742762
public static boolean checkpw(String plaintext, String hashed) {
743-
return equalsNoEarlyReturn(hashed, hashpw(plaintext, hashed));
763+
byte[] passwordb = plaintext.getBytes(StandardCharsets.UTF_8);
764+
return equalsNoEarlyReturn(hashed, hashpwforcheck(passwordb, hashed));
744765
}
745766

746767
/**
@@ -751,7 +772,7 @@ public static boolean checkpw(String plaintext, String hashed) {
751772
* @since 5.3
752773
*/
753774
public static boolean checkpw(byte[] passwordb, String hashed) {
754-
return equalsNoEarlyReturn(hashed, hashpw(passwordb, hashed));
775+
return equalsNoEarlyReturn(hashed, hashpwforcheck(passwordb, hashed));
755776
}
756777

757778
static boolean equalsNoEarlyReturn(String a, String b) {

crypto/src/test/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoderTests.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,4 +208,18 @@ public void matchNullRawPassword() {
208208
assertThatIllegalArgumentException().isThrownBy(() -> encoder.matches(null, "does-not-matter"));
209209
}
210210

211+
@Test
212+
public void upgradeWhenNoRoundsThenTrue() {
213+
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
214+
assertThat(encoder.upgradeEncoding("$2a$00$9N8N35BVs5TLqGL3pspAte5OWWA2a2aZIs.EGp7At7txYakFERMue")).isTrue();
215+
}
216+
217+
@Test
218+
public void checkWhenNoRoundsThenTrue() {
219+
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
220+
assertThat(encoder.matches("password", "$2a$00$9N8N35BVs5TLqGL3pspAte5OWWA2a2aZIs.EGp7At7txYakFERMue"))
221+
.isTrue();
222+
assertThat(encoder.matches("wrong", "$2a$00$9N8N35BVs5TLqGL3pspAte5OWWA2a2aZIs.EGp7At7txYakFERMue")).isFalse();
223+
}
224+
211225
}

crypto/src/test/java/org/springframework/security/crypto/bcrypt/BCryptTests.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,4 +456,11 @@ public void equalsOnStringsIsCorrect() {
456456
assertThat(BCrypt.equalsNoEarlyReturn("test", "pass")).isFalse();
457457
}
458458

459+
@Test
460+
public void checkpwWhenZeroRoundsThenMatches() {
461+
String password = "$2a$00$9N8N35BVs5TLqGL3pspAte5OWWA2a2aZIs.EGp7At7txYakFERMue";
462+
assertThat(BCrypt.checkpw("password", password)).isTrue();
463+
assertThat(BCrypt.checkpw("wrong", password)).isFalse();
464+
}
465+
459466
}

0 commit comments

Comments
 (0)