From dc7d998a5ee297ba4d6b736d4aad9a476b0a2f21 Mon Sep 17 00:00:00 2001 From: Patrick Favre-Bulle Date: Sat, 19 Oct 2019 18:35:58 +0200 Subject: [PATCH 1/3] Add long-password strategy to verifier refs #21 --- CHANGELOG | 1 + README.md | 10 ++++++++-- .../at/favre/lib/crypto/bcrypt/BCrypt.java | 19 ++++++++++++++++--- .../crypto/bcrypt/LongPasswordStrategies.java | 9 +++++++++ .../crypto/bcrypt/LongPasswordStrategy.java | 9 +++++++++ .../favre/lib/crypto/bcrypt/BcryptTest.java | 11 +++++++++++ .../bcrypt/LongPasswordStrategyTest.java | 12 ++++++++++++ 7 files changed, 66 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c1fa3c7..8648e22 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 ## v0.8.0 diff --git a/README.md b/README.md index 5a6b32f..0471783 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 83ca6ec..015731d 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,9 +121,20 @@ 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); + } /** * Can create bcrypt hashes */ @@ -364,8 +375,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; } /** @@ -548,7 +561,7 @@ public Result verify(byte[] password, int cost, byte[] salt, byte[] rawBcryptHas Objects.requireNonNull(rawBcryptHash23Bytes); Objects.requireNonNull(salt); - HashData hashData = BCrypt.withDefaults().hashRaw(cost, salt, password); + HashData hashData = BCrypt.with(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 f1bc563..1ed8717 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 @@ -410,4 +410,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)); + } + } } From f44063ac2e8d3e3113fe7aa0476f3fe9192b1b90 Mon Sep 17 00:00:00 2001 From: Patrick Favre-Bulle Date: Sun, 20 Oct 2019 10:27:47 +0200 Subject: [PATCH 2/3] Fix checkstyle issue --- .../bcrypt/src/main/java/at/favre/lib/crypto/bcrypt/BCrypt.java | 1 + 1 file changed, 1 insertion(+) 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 015731d..7d5d911 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 @@ -135,6 +135,7 @@ public static Verifyer verifyer() { public static Verifyer verifyer(LongPasswordStrategy longPasswordStrategy) { return new Verifyer(longPasswordStrategy); } + /** * Can create bcrypt hashes */ From 682c322ac4d7f1f92c86ae73432877515251b5cc Mon Sep 17 00:00:00 2001 From: Patrick Favre-Bulle Date: Sun, 20 Oct 2019 12:11:06 +0200 Subject: [PATCH 3/3] Fix small issue in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0471783..9bb2308 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ BCrypt.with(LongPasswordStrategies.hashSha512()).hash(6, pw); //allows to honour Don't forget to use the same strategy when verifying: ```java -BCrypt.verifyer(LongPasswordStrategies.truncate()).verify(pw, hash) +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