BCryptPasswordEncoder validates strength

Fixes gh-3862
This commit is contained in:
Kim Saabye Pedersen 2016-05-04 19:05:24 +02:00 committed by Rob Winch
parent 101190ad8b
commit 9fcfeaf225
3 changed files with 25 additions and 10 deletions

View File

@ -257,6 +257,8 @@ public class BCrypt {
8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
-1, -1, -1, -1, -1, -1, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, -1, -1, -1, -1, -1, -1, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, -1, -1, -1, -1, -1 }; 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, -1, -1, -1, -1, -1 };
static final int MIN_LOG_ROUNDS = 4;
static final int MAX_LOG_ROUNDS = 31;
// Expanded Blowfish key // Expanded Blowfish key
private int P[]; private int P[];
private int S[]; private int S[];
@ -600,12 +602,12 @@ public class BCrypt {
/** /**
* Generate a salt for use with the BCrypt.hashpw() method * 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 * @param log_rounds the log2 of the number of rounds of hashing to apply - the work
* factor therefore increases as 2**log_rounds. * factor therefore increases as 2**log_rounds. Minimum 4, maximum 31.
* @param random an instance of SecureRandom to use * @param random an instance of SecureRandom to use
* @return an encoded salt value * @return an encoded salt value
*/ */
public static String gensalt(int log_rounds, SecureRandom random) { public static String gensalt(int log_rounds, SecureRandom random) {
if (log_rounds < 4 || log_rounds > 31) { if (log_rounds < MIN_LOG_ROUNDS || log_rounds > MAX_LOG_ROUNDS) {
throw new IllegalArgumentException("Bad number of rounds"); throw new IllegalArgumentException("Bad number of rounds");
} }
StringBuilder rs = new StringBuilder(); StringBuilder rs = new StringBuilder();
@ -626,7 +628,7 @@ public class BCrypt {
/** /**
* Generate a salt for use with the BCrypt.hashpw() method * 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 * @param log_rounds the log2 of the number of rounds of hashing to apply - the work
* factor therefore increases as 2**log_rounds. * factor therefore increases as 2**log_rounds. Minimum 4, maximum 31.
* @return an encoded salt value * @return an encoded salt value
*/ */
public static String gensalt(int log_rounds) { public static String gensalt(int log_rounds) {

View File

@ -15,13 +15,13 @@
*/ */
package org.springframework.security.crypto.bcrypt; package org.springframework.security.crypto.bcrypt;
import java.security.SecureRandom;
import java.util.regex.Pattern;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import java.security.SecureRandom;
import java.util.regex.Pattern;
/** /**
* Implementation of PasswordEncoder that uses the BCrypt strong hashing function. Clients * Implementation of PasswordEncoder that uses the BCrypt strong hashing function. Clients
* can optionally supply a "strength" (a.k.a. log rounds in BCrypt) and a SecureRandom * can optionally supply a "strength" (a.k.a. log rounds in BCrypt) and a SecureRandom
@ -45,18 +45,21 @@ public class BCryptPasswordEncoder implements PasswordEncoder {
} }
/** /**
* @param strength the log rounds to use * @param strength the log rounds to use, between 4 and 31
*/ */
public BCryptPasswordEncoder(int strength) { public BCryptPasswordEncoder(int strength) {
this(strength, null); this(strength, null);
} }
/** /**
* @param strength the log rounds to use * @param strength the log rounds to use, between 4 and 31
* @param random the secure random instance to use * @param random the secure random instance to use
* *
*/ */
public BCryptPasswordEncoder(int strength, SecureRandom random) { public BCryptPasswordEncoder(int strength, SecureRandom random) {
if (strength != -1 && (strength < BCrypt.MIN_LOG_ROUNDS || strength > BCrypt.MAX_LOG_ROUNDS)) {
throw new IllegalArgumentException("Bad strength");
}
this.strength = strength; this.strength = strength;
this.random = random; this.random = random;
} }

View File

@ -15,12 +15,12 @@
*/ */
package org.springframework.security.crypto.bcrypt; package org.springframework.security.crypto.bcrypt;
import static org.assertj.core.api.Assertions.*;
import org.junit.Test; import org.junit.Test;
import java.security.SecureRandom; import java.security.SecureRandom;
import static org.assertj.core.api.Assertions.assertThat;
/** /**
* @author Dave Syer * @author Dave Syer
* *
@ -57,6 +57,16 @@ public class BCryptPasswordEncoderTests {
assertThat(encoder.matches("password", result)).isTrue(); assertThat(encoder.matches("password", result)).isTrue();
} }
@Test(expected = IllegalArgumentException.class)
public void badLowCustomStrength() {
new BCryptPasswordEncoder(3);
}
@Test(expected = IllegalArgumentException.class)
public void badHighCustomStrength() {
new BCryptPasswordEncoder(32);
}
@Test @Test
public void customRandom() { public void customRandom() {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(8, new SecureRandom()); BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(8, new SecureRandom());