From 9fcfeaf2257abece87ce4f6a8d55b5c1128f3320 Mon Sep 17 00:00:00 2001 From: Kim Saabye Pedersen Date: Wed, 4 May 2016 19:05:24 +0200 Subject: [PATCH] BCryptPasswordEncoder validates strength Fixes gh-3862 --- .../security/crypto/bcrypt/BCrypt.java | 8 +++++--- .../crypto/bcrypt/BCryptPasswordEncoder.java | 13 ++++++++----- .../crypto/bcrypt/BCryptPasswordEncoderTests.java | 14 ++++++++++++-- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCrypt.java b/crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCrypt.java index 77a0592ce3..d6f0890ccf 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCrypt.java +++ b/crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCrypt.java @@ -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, -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 }; + static final int MIN_LOG_ROUNDS = 4; + static final int MAX_LOG_ROUNDS = 31; // Expanded Blowfish key private int P[]; private int S[]; @@ -600,12 +602,12 @@ public class BCrypt { /** * 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. + * factor therefore increases as 2**log_rounds. Minimum 4, maximum 31. * @param random an instance of SecureRandom to use * @return an encoded salt value */ 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"); } StringBuilder rs = new StringBuilder(); @@ -626,7 +628,7 @@ public class BCrypt { /** * 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. + * factor therefore increases as 2**log_rounds. Minimum 4, maximum 31. * @return an encoded salt value */ public static String gensalt(int log_rounds) { diff --git a/crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.java b/crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.java index a18de67fc7..b313b1a730 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.java +++ b/crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.java @@ -15,13 +15,13 @@ */ 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.LogFactory; - 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 * 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) { 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 * */ 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.random = random; } diff --git a/crypto/src/test/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoderTests.java b/crypto/src/test/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoderTests.java index a792a6b299..998b0890c4 100644 --- a/crypto/src/test/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoderTests.java +++ b/crypto/src/test/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoderTests.java @@ -15,12 +15,12 @@ */ package org.springframework.security.crypto.bcrypt; -import static org.assertj.core.api.Assertions.*; - import org.junit.Test; import java.security.SecureRandom; +import static org.assertj.core.api.Assertions.assertThat; + /** * @author Dave Syer * @@ -57,6 +57,16 @@ public class BCryptPasswordEncoderTests { 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 public void customRandom() { BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(8, new SecureRandom());