From 280218068c86fac7421545eba92678f24697c71d Mon Sep 17 00:00:00 2001 From: firaja Date: Thu, 8 Dec 2022 10:54:56 +0100 Subject: [PATCH] #92: fixed inconsistency of Argon2 during salt encoding --- CHANGELOG.md | 4 +++ .../java/com/password4j/Argon2Function.java | 16 +++++----- src/test/com/password4j/PasswordTest.java | 32 +++++++++++++++---- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ae27171..0102d89c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## [1.6.3](https://github.com/Password4j/password4j/releases/tag/1.6.3) - (2022-12-08) +### Fixed +* Inconsistency of Argon2 with some kind of salts generated from external libraries [#92](../../issues/92) + ## [1.6.2](https://github.com/Password4j/password4j/releases/tag/1.6.2) - (2022-10-20) ### Added * Application banner ([#83](../../issues/83)). diff --git a/src/main/java/com/password4j/Argon2Function.java b/src/main/java/com/password4j/Argon2Function.java index 8385ea74..61cee196 100644 --- a/src/main/java/com/password4j/Argon2Function.java +++ b/src/main/java/com/password4j/Argon2Function.java @@ -18,6 +18,7 @@ import com.password4j.types.Argon2; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -346,11 +347,10 @@ private Hash internalHash(CharSequence plainTextPassword, byte[] salt, CharSeque { salt = SaltGenerator.generate(); } - String theSalt = Utils.fromBytesToString(salt); initialize(password, salt, Utils.fromCharSequenceToBytes(pepper), null, blockMemory); fillMemoryBlocks(blockMemory); byte[] hash = ending(blockMemory); - Hash result = new Hash(this, encodeHash(hash, theSalt), hash, theSalt); + Hash result = new Hash(this, encodeHash(hash, salt), hash, Utils.fromBytesToString(salt)); result.setPepper(pepper); return result; } @@ -365,18 +365,18 @@ public boolean check(CharSequence plainTextPassword, String hashed) @Override public boolean check(CharSequence plainTextPassword, String hashed, String salt, CharSequence pepper) { - String theSalt; + byte[] theSalt; if (salt == null) { Object[] params = decodeHash(hashed); - theSalt = Utils.fromBytesToString((byte[]) params[5]); + theSalt = (byte[]) params[5]; } else { - theSalt = salt; + theSalt = salt.getBytes(StandardCharsets.UTF_8); } - Hash internalHash = hash(plainTextPassword, theSalt, pepper); + Hash internalHash = internalHash(plainTextPassword, theSalt, pepper); return slowEquals(internalHash.getResult(), hashed); } @@ -800,11 +800,11 @@ private static String remove(String source, String remove) return source.substring(remove.length()); } - private String encodeHash(byte[] hash, String salt) + private String encodeHash(byte[] hash, byte[] salt) { return "$argon2" + variant.name() .toLowerCase() + "$v=" + version + "$m=" + memory + ",t=" + iterations + ",p=" + parallelism + "$" - + Utils.encodeBase64(Utils.fromCharSequenceToBytes(salt), false) + "$" + + Utils.encodeBase64(salt, false) + "$" + Utils.encodeBase64(hash, false); } diff --git a/src/test/com/password4j/PasswordTest.java b/src/test/com/password4j/PasswordTest.java index 09fc8c84..f9e59cde 100644 --- a/src/test/com/password4j/PasswordTest.java +++ b/src/test/com/password4j/PasswordTest.java @@ -16,11 +16,8 @@ */ package com.password4j; -import com.password4j.types.Argon2; -import com.password4j.types.Bcrypt; -import com.password4j.types.Hmac; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.io.ByteArrayOutputStream; import java.io.PrintStream; @@ -29,7 +26,12 @@ import java.security.Security; import java.util.Random; -import static org.junit.Assert.assertTrue; +import org.junit.Assert; +import org.junit.Test; + +import com.password4j.types.Argon2; +import com.password4j.types.Bcrypt; +import com.password4j.types.Hmac; public class PasswordTest @@ -854,5 +856,23 @@ public void testMultiUnicode() Assert.assertEquals(hash, hash2); } + /** + * @see issue #92 + */ + @Test + public void issue92() + { + String hash = "$argon2id$v=19$m=16384,t=2,p=1$nlm7oNI5zquzSYkyby6oVw$JOkJAYrDB0i2gmiJrXC6o2r+u1rszCm/RO9gIQtnxlY"; + String plain = "Test123!"; + Argon2Function function = Argon2Function.getInstanceFromHash(hash); + + boolean verified = Password.check(plain, hash).with(function); + Hash newHash = Password.hash(plain).addSalt("Y9ΫI2o.W").with(function); + boolean verified2 = Password.check(plain, newHash); + + assertTrue(verified); + assertTrue(verified2); + assertEquals("$argon2id$v=19$m=16384,t=2,p=1$WTnOq0kyby5X$SewIdM+Ywctw0lfNQ0xKYoUIlyRs3qF+gVmEVtpdmyg", newHash.getResult()); + } }