Fix salt derivation and KDF byte derivation

This commit is contained in:
sergeych committed 2026-05-30 15:48:48 +03:00
1 parent 2d55af4e3b
commit ff494ab4ef
5 files changed
+121 -49

No files matched your search

+27 -10
View File
@@ -55,15 +55,33 @@ class HashTest {
@Test
fun deriveSaltTest() = runTest {
initCrypto()
for( i in 2..257 ) {
val x = Hash.Sha3AndBlake.deriveSalt("base one", i)
val y = Hash.Sha3AndBlake.deriveSalt("base one", i)
val z = Hash.Sha3AndBlake.deriveSalt("base two", i)
assertContentEquals(x, y)
assertFalse { x contentEquals z }
assertEquals(x.size, i)
assertEquals(y.size, i)
assertEquals(z.size, i)
for (hash in Hash.entries) {
for (i in 1..257) {
val x = hash.deriveSalt("base one", i)
val y = hash.deriveSalt("base one", i)
val z = hash.deriveSalt("base two", i)
assertContentEquals(x, y)
if (i > 1) assertFalse { x contentEquals z }
assertEquals(i, x.size)
assertEquals(i, y.size)
assertEquals(i, z.size)
}
}
}
@Test
fun deriveSaltFromBytesTest() = runTest {
initCrypto()
val base = "base one".encodeToByteArray().asUByteArray()
for (hash in Hash.entries) {
for (i in listOf(1, 5, 31, 32, 33, 96, 97)) {
val fromString = hash.deriveSalt("base one", i)
val fromBytes = hash.deriveSaltFromBytes(base, i)
val fromTypoAlias = hash.deriveSaltFormBytes(base, i)
assertEquals(i, fromBytes.size)
assertContentEquals(fromString, fromBytes)
assertContentEquals(fromBytes, fromTypoAlias)
}
}
}
@@ -78,4 +96,3 @@ suspend fun <T> sw(label: String, f: suspend () -> T): T {
return result
}
+32 -16
View File
@@ -16,7 +16,6 @@ import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertFailsWith
import kotlin.test.assertIs
class KDFTest {
@@ -63,18 +62,34 @@ class KDFTest {
fun complexityKdfForSizeInBytesTest() = runTest {
initCrypto()
val size = KDF.Argon.minKeySize + 17
val domain = "kdf-size-in-bytes-test"
val expectedSalt = Hash.Blake2b.deriveSalt(domain, KDF.Argon.saltSize)
val expectedSalt = UByteArray(KDF.Argon.saltSize) { (it + 3).toUByte() }
val kdf = KDF.Complexity.FixedLow.kdfForSizeInBytes(size, domain)
val kdf = KDF.Complexity.FixedLow.kdfForSizeInBytes(size, expectedSalt)
assertIs<KDF.Argon>(kdf)
assertEquals(KDF.Argon.create(KDF.Complexity.FixedLow, expectedSalt, size), kdf)
assertEquals(size, kdf.keySize)
assertContentEquals(expectedSalt, kdf.salt)
assertFalse {
kdf.salt contentEquals Hash.Blake2b.deriveSalt("$domain-other", KDF.Argon.saltSize)
}
}
@Test
fun createDefaultNormalizesSaltTest() = runTest {
initCrypto()
val size = KDF.Argon.minKeySize + 19
val shortSalt = ubyteArrayOf(1u, 2u, 3u, 4u, 5u)
val longSalt = UByteArray(KDF.Argon.saltSize + 7) { (it * 5).toUByte() }
val expectedShortSalt = Hash.Blake2b.deriveSaltFormBytes(shortSalt, KDF.Argon.saltSize)
val expectedLongSalt = Hash.Blake2b.deriveSaltFormBytes(longSalt, KDF.Argon.saltSize)
val shortKdf = KDF.createDefault(size, KDF.Complexity.FixedLow, shortSalt)
val longKdf = KDF.Complexity.FixedLow.kdfForSizeInBytes(size, longSalt)
assertIs<KDF.Argon>(shortKdf)
assertIs<KDF.Argon>(longKdf)
assertEquals(KDF.Argon.saltSize, shortKdf.salt.size)
assertEquals(KDF.Argon.saltSize, longKdf.salt.size)
assertContentEquals(expectedShortSalt, shortKdf.salt)
assertContentEquals(expectedLongSalt, longKdf.salt)
}
@Test
@@ -84,9 +99,9 @@ class KDFTest {
val kdf = KDF.Argon.create(KDF.Complexity.Interactive, salt, 80)
val source = UByteArray(47) { (it * 3).toUByte() }
val b1 = kdf.deriveFromBytes(source, 80)
val b2 = kdf.deriveFromBytes(source, 80)
val b3 = kdf.deriveFromBytes(source + 1u, 80)
val b1 = kdf.deriveFromBytes(source)
val b2 = kdf.deriveFromBytes(source)
val b3 = kdf.deriveFromBytes(source + 1u)
assertEquals(80, b1.size)
assertContentEquals(b1, b2)
@@ -100,21 +115,22 @@ class KDFTest {
val source = UByteArray(23) { (it + 7).toUByte() }
val b1 = KDF.Complexity.Interactive.derive(source, salt, 64)
val b2 = KDF.Argon.create(KDF.Complexity.Interactive, salt, 64).deriveFromBytes(source, 64)
val b2 = KDF.Argon.create(KDF.Complexity.Interactive, salt, 64).deriveFromBytes(source)
assertContentEquals(b1, b2)
assertEquals(64, b1.size)
}
@Test
fun deriveFromBytesValidationTest() = runTest {
fun deriveFromBytesUsesKeySizeTest() = runTest {
initCrypto()
val salt = UByteArray(KDF.Argon.saltSize) { it.toUByte() }
val kdf = KDF.Argon.create(KDF.Complexity.Interactive, salt, KDF.Argon.minKeySize)
val source = ubyteArrayOf(1u, 2u, 3u)
val shortKdf = KDF.Argon.create(KDF.Complexity.Interactive, salt, 64)
val longKdf = KDF.Argon.create(KDF.Complexity.Interactive, salt, 96)
assertFailsWith<IllegalArgumentException> {
kdf.deriveFromBytes(ubyteArrayOf(1u, 2u, 3u), KDF.Argon.minKeySize - 1)
}
assertEquals(64, shortKdf.deriveFromBytes(source).size)
assertEquals(96, longKdf.deriveFromBytes(source).size)
}
}