diff --git a/CHANGELOG b/CHANGELOG index 4199f81..d20c9f1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,7 @@ ## v0.9.0 * fix license headers and correct credits to jBcrypt +* add long-password strategy to verifier #21 * fix not returning correct hash version when verifying #24 ### Breaking Changes diff --git a/README.md b/README.md index 5a6b32f..9bb2308 100644 --- a/README.md +++ b/README.md @@ -101,8 +101,14 @@ The API supports passing a custom handling in that case, to mimic the behaviour truncate the password. ```java -BCrypt.with(LongPasswordStrategies.truncate()).hash(6, new byte[100]); -BCrypt.with(LongPasswordStrategies.hashSha512()).hash(6, new byte[100]); //allows to honour all pw bytes +BCrypt.with(LongPasswordStrategies.truncate()).hash(6, pw); +BCrypt.with(LongPasswordStrategies.hashSha512()).hash(6, pw); //allows to honour all pw bytes +``` + +Don't forget to use the same strategy when verifying: + +```java +BCrypt.verifyer(LongPasswordStrategies.truncate()).verify(pw, hash); ``` The password will only be transformed if it is longer than 71 bytes. *It is important to note, however, that using any diff --git a/modules/bcrypt/src/main/java/at/favre/lib/crypto/bcrypt/BCrypt.java b/modules/bcrypt/src/main/java/at/favre/lib/crypto/bcrypt/BCrypt.java index 2e6daf6..998fe20 100644 --- a/modules/bcrypt/src/main/java/at/favre/lib/crypto/bcrypt/BCrypt.java +++ b/modules/bcrypt/src/main/java/at/favre/lib/crypto/bcrypt/BCrypt.java @@ -121,7 +121,19 @@ public static Hasher with(Version version, SecureRandom secureRandom, LongPasswo * @return new verifier instance */ public static Verifyer verifyer() { - return new Verifyer(); + return verifyer(LongPasswordStrategies.none()); + } + + /** + * Creates a new instance of bcrypt verifier to verify a password against a given hash. + * This verify also respects the passed {@link LongPasswordStrategy} for creating the reference hash - use this + * if you use one while hashing. + * + * @param longPasswordStrategy used to create the reference hash. + * @return new verifier instance + */ + public static Verifyer verifyer(LongPasswordStrategy longPasswordStrategy) { + return new Verifyer(longPasswordStrategy); } /** @@ -364,8 +376,10 @@ public String toString() { */ public static final class Verifyer { private final Charset defaultCharset = DEFAULT_CHARSET; + private final LongPasswordStrategy longPasswordStrategy; - private Verifyer() { + private Verifyer(LongPasswordStrategy longPasswordStrategy) { + this.longPasswordStrategy = longPasswordStrategy; } /** @@ -549,7 +563,7 @@ public Result verify(byte[] password, int cost, byte[] salt, byte[] rawBcryptHas Objects.requireNonNull(rawBcryptHash23Bytes); Objects.requireNonNull(salt); - HashData hashData = BCrypt.with(version).hashRaw(cost, salt, password); + HashData hashData = BCrypt.with(version, new SecureRandom(), longPasswordStrategy).hashRaw(cost, salt, password); return new Result(hashData, Bytes.wrap(hashData.rawHash).equalsConstantTime(rawBcryptHash23Bytes)); } } diff --git a/modules/bcrypt/src/main/java/at/favre/lib/crypto/bcrypt/LongPasswordStrategies.java b/modules/bcrypt/src/main/java/at/favre/lib/crypto/bcrypt/LongPasswordStrategies.java index dc6e86e..83b6931 100644 --- a/modules/bcrypt/src/main/java/at/favre/lib/crypto/bcrypt/LongPasswordStrategies.java +++ b/modules/bcrypt/src/main/java/at/favre/lib/crypto/bcrypt/LongPasswordStrategies.java @@ -34,4 +34,13 @@ public static LongPasswordStrategy hashSha512() { public static LongPasswordStrategy strict() { return new LongPasswordStrategy.StrictMaxPasswordLengthStrategy(BCrypt.MAX_PW_LENGTH_BYTE); } + + /** + * See {@link LongPasswordStrategy.PassThroughStrategy} + * + * @return new instance + */ + public static LongPasswordStrategy none() { + return new LongPasswordStrategy.PassThroughStrategy(); + } } diff --git a/modules/bcrypt/src/main/java/at/favre/lib/crypto/bcrypt/LongPasswordStrategy.java b/modules/bcrypt/src/main/java/at/favre/lib/crypto/bcrypt/LongPasswordStrategy.java index ed05cbd..cd7a5b4 100644 --- a/modules/bcrypt/src/main/java/at/favre/lib/crypto/bcrypt/LongPasswordStrategy.java +++ b/modules/bcrypt/src/main/java/at/favre/lib/crypto/bcrypt/LongPasswordStrategy.java @@ -83,4 +83,13 @@ public byte[] innerDerive(byte[] rawPassword) { } } + /** + * A simple strategy that just returns the provided password without changing it. + */ + final class PassThroughStrategy implements LongPasswordStrategy { + @Override + public byte[] derive(byte[] rawPassword) { + return rawPassword; + } + } } diff --git a/modules/bcrypt/src/test/java/at/favre/lib/crypto/bcrypt/BcryptTest.java b/modules/bcrypt/src/test/java/at/favre/lib/crypto/bcrypt/BcryptTest.java index c80569b..31b7d8d 100644 --- a/modules/bcrypt/src/test/java/at/favre/lib/crypto/bcrypt/BcryptTest.java +++ b/modules/bcrypt/src/test/java/at/favre/lib/crypto/bcrypt/BcryptTest.java @@ -413,4 +413,15 @@ public void testVersionPojoMethods() { assertNotEquals(BCrypt.Version.VERSION_2A.hashCode(), BCrypt.Version.VERSION_2B.hashCode()); assertNotEquals(BCrypt.Version.VERSION_2X.hashCode(), BCrypt.Version.VERSION_2Y.hashCode()); } + + @Test + public void testVerifierWithLongPasswordStrategy() { + LongPasswordStrategy truncate = LongPasswordStrategies.truncate(); + + byte[] pw = Bytes.random(200).array(); + byte[] hash = BCrypt.with(truncate).hash(4, pw); + + assertTrue(BCrypt.verifyer(truncate).verify(pw, hash).verified); + assertFalse(BCrypt.verifyer().verify(pw, hash).verified); + } } diff --git a/modules/bcrypt/src/test/java/at/favre/lib/crypto/bcrypt/LongPasswordStrategyTest.java b/modules/bcrypt/src/test/java/at/favre/lib/crypto/bcrypt/LongPasswordStrategyTest.java index 89fe79f..9027d8b 100644 --- a/modules/bcrypt/src/test/java/at/favre/lib/crypto/bcrypt/LongPasswordStrategyTest.java +++ b/modules/bcrypt/src/test/java/at/favre/lib/crypto/bcrypt/LongPasswordStrategyTest.java @@ -14,6 +14,7 @@ public class LongPasswordStrategyTest { public void testFactory() { assertNotNull(LongPasswordStrategies.hashSha512().derive(Bytes.random(100).array())); assertNotNull(LongPasswordStrategies.truncate().derive(Bytes.random(100).array())); + assertNotNull(LongPasswordStrategies.none().derive(Bytes.random(100).array())); } @Test(expected = IllegalArgumentException.class) @@ -92,4 +93,15 @@ public void testSha512HashStrategy() { System.out.println(Bytes.wrap(byteArray).encodeHex()); } } + + @Test + public void testPassThroughStrategy() { + LongPasswordStrategy strategy = new LongPasswordStrategy.PassThroughStrategy(); + byte[] byteArray; + + for (int i = 1; i < 64; i++) { + byteArray = Bytes.random(i).array(); + assertSame(byteArray, strategy.derive(byteArray)); + } + } }