From c2f0f26045db040d6e5ddc0f8138aa2b71907a48 Mon Sep 17 00:00:00 2001 From: Patrick Favre-Bulle Date: Sun, 20 Oct 2019 11:43:57 +0200 Subject: [PATCH] Fix not returning correct hash version when verifying [Breaking API Change] refs #24 --- CHANGELOG | 5 ++ .../at/favre/lib/crypto/bcrypt/BCrypt.java | 9 ++-- .../favre/lib/crypto/bcrypt/BcryptTest.java | 53 ++++++++++--------- 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c1fa3c7..4199f81 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,11 @@ ## v0.9.0 * fix license headers and correct credits to jBcrypt +* fix not returning correct hash version when verifying #24 + +### Breaking Changes + +* `verify(byte[] password, int cost, byte[] salt, byte[] rawBcryptHash23Bytes)` signature changed, added `version` property (see #24) ## v0.8.0 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..2e6daf6 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 @@ -503,7 +503,7 @@ private Result verify(byte[] password, byte[] bcryptHash, Version requiredVersio return new Result(hashData, false); } - return verify(password, hashData.cost, hashData.rawSalt, hashData.rawHash); + return verify(password, hashData.cost, hashData.rawSalt, hashData.rawHash, hashData.version); } catch (IllegalBCryptFormatException e) { return new Result(e); } @@ -524,7 +524,7 @@ private Result verify(byte[] password, byte[] bcryptHash, Version requiredVersio * @return result object, see {@link Result} for more info */ public Result verify(byte[] password, HashData bcryptHashData) { - return verify(password, bcryptHashData.cost, bcryptHashData.rawSalt, bcryptHashData.rawHash); + return verify(password, bcryptHashData.cost, bcryptHashData.rawSalt, bcryptHashData.rawHash, bcryptHashData.version); } /** @@ -541,14 +541,15 @@ public Result verify(byte[] password, HashData bcryptHashData) { * @param cost cost (log2 factor) which was used to create the hash * @param salt 16 byte raw hash value (not radix64 version) which was used to create the hash * @param rawBcryptHash23Bytes 23 byte raw bcrypt hash value (not radix64 version) + * @param version the version of the provided hash * @return result object, see {@link Result} for more info */ - public Result verify(byte[] password, int cost, byte[] salt, byte[] rawBcryptHash23Bytes) { + public Result verify(byte[] password, int cost, byte[] salt, byte[] rawBcryptHash23Bytes, Version version) { Objects.requireNonNull(password); Objects.requireNonNull(rawBcryptHash23Bytes); Objects.requireNonNull(salt); - HashData hashData = BCrypt.withDefaults().hashRaw(cost, salt, password); + HashData hashData = BCrypt.with(version).hashRaw(cost, salt, password); return new Result(hashData, Bytes.wrap(hashData.rawHash).equalsConstantTime(rawBcryptHash23Bytes)); } } 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..c80569b 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 @@ -263,23 +263,17 @@ public void verifyWithResult() { byte[] hash = bCrypt.hash(8, Bytes.random(16).array(), pw); BCrypt.Result result = BCrypt.verifyer().verify(pw, hash); - assertTrue(result.verified); - assertTrue(result.validFormat); - assertEquals(BCrypt.Version.VERSION_2A, result.details.version); - assertEquals(8, result.details.cost); + assertResult(result, true, BCrypt.Version.VERSION_2A, 8); } @Test public void verifyRawByteArrays() { BCrypt.Hasher bCrypt = BCrypt.withDefaults(); - byte[] pw = Bytes.random(24).encodeBase36().getBytes(); + byte[] pw = Bytes.random(24).encodeRadix(36).getBytes(); BCrypt.HashData hash = bCrypt.hashRaw(6, Bytes.random(16).array(), pw); BCrypt.Result result = BCrypt.verifyer().verify(pw, hash); - assertTrue(result.verified); - assertTrue(result.validFormat); - assertEquals(BCrypt.Version.VERSION_2A, result.details.version); - assertEquals(6, result.details.cost); + assertResult(result, true, BCrypt.Version.VERSION_2A, 6); } @Test @@ -288,11 +282,8 @@ public void verifyRawByteArrays2() { byte[] pw = Bytes.random(24).encodeBase36().getBytes(); BCrypt.HashData hash = bCrypt.hashRaw(7, Bytes.random(16).array(), pw); - BCrypt.Result result = BCrypt.verifyer().verify(pw, hash.cost, hash.rawSalt, hash.rawHash); - assertTrue(result.verified); - assertTrue(result.validFormat); - assertEquals(BCrypt.Version.VERSION_2A, result.details.version); - assertEquals(7, result.details.cost); + BCrypt.Result result = BCrypt.verifyer().verify(pw, hash.cost, hash.rawSalt, hash.rawHash, hash.version); + assertResult(result, true, BCrypt.Version.VERSION_2A, 7); } @Test @@ -302,10 +293,7 @@ public void verifyWithResultChars() { char[] hash = bCrypt.hashToChar(6, pw.toCharArray()); BCrypt.Result result = BCrypt.verifyer().verify(pw.toCharArray(), hash); - assertTrue(result.verified); - assertTrue(result.validFormat); - assertEquals(BCrypt.Version.VERSION_2A, result.details.version); - assertEquals(6, result.details.cost); + assertResult(result, true, BCrypt.Version.VERSION_2A, 6); } @Test @@ -315,10 +303,7 @@ public void verifyIncorrectStrictVersion() { byte[] hash = bCrypt.hash(5, Bytes.random(16).array(), pw); BCrypt.Result result = BCrypt.verifyer().verifyStrict(pw, hash, BCrypt.Version.VERSION_2A); - assertFalse(result.verified); - assertTrue(result.validFormat); - assertEquals(BCrypt.Version.VERSION_2Y, result.details.version); - assertEquals(5, result.details.cost); + assertResult(result, false, BCrypt.Version.VERSION_2Y, 5); } @Test @@ -328,10 +313,28 @@ public void verifyIncorrectStrictVersionChars() { char[] hash = bCrypt.hashToChar(5, pw.toCharArray()); BCrypt.Result result = BCrypt.verifyer().verifyStrict(pw.toCharArray(), hash, BCrypt.Version.VERSION_2A); - assertFalse(result.verified); + assertResult(result, false, BCrypt.Version.VERSION_2X, 5); + } + + @Test + public void verifyCorrectNonDefaultVersion() { + BCrypt.Version version = BCrypt.Version.VERSION_2X; + int cost = 4; + BCrypt.Hasher bCrypt = BCrypt.with(version); + String pw = "8PAsdjhlkjhkjla_ääas#d"; + BCrypt.HashData hash1 = bCrypt.hashRaw(cost, Bytes.random(16).array(), Bytes.from(pw).array()); + char[] hash2 = bCrypt.hashToChar(cost, pw.toCharArray()); + + assertResult(BCrypt.verifyer().verify(pw.toCharArray(), hash2), true, version, cost); + assertResult(BCrypt.verifyer().verifyStrict(pw.toCharArray(), hash2, version), true, version, cost); + assertResult(BCrypt.verifyer().verify(Bytes.from(pw).array(), hash1), true, version, cost); + } + + private void assertResult(BCrypt.Result result, boolean verified, BCrypt.Version version, int cost) { + assertEquals(verified, result.verified); assertTrue(result.validFormat); - assertEquals(BCrypt.Version.VERSION_2X, result.details.version); - assertEquals(5, result.details.cost); + assertEquals(version, result.details.version); + assertEquals(cost, result.details.cost); } @Test