137 lines
4.7 KiB
Kotlin

/*
* Copyright (c) 2025. Sergey S. Chernov - All Rights Reserved
*
* You may use, distribute and modify this code under the
* terms of the private license, which you must obtain from the author
*
* To obtain the license, contact the author: https://t.me/real_sergeych or email to
* real dot sergeych at gmail.
*/
import kotlinx.coroutines.test.runTest
import net.sergeych.crypto2.Hash
import net.sergeych.crypto2.KDF
import net.sergeych.crypto2.initCrypto
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertIs
class KDFTest {
@Test
fun testCacheKey() = runTest{
initCrypto()
val k1 = KDF.Argon.create(KDF.Complexity.Interactive, KDF.Argon.randomSalt(), 128)
val k2 = KDF.Argon.create(KDF.Complexity.Interactive, k1.salt, 128)
assertEquals(k1, k2)
assertEquals(k1.hashCode(), k2.hashCode())
val key1 = KDF.Instance(k1, "foo")
val key2 = KDF.Instance(k2, "foo")
val key3 = KDF.Instance(k2, "bar")
assertEquals(key1, key2)
assertEquals(key1.hashCode(), key2.hashCode())
assertFalse { key3 == key2 }
assertFalse { key3.hashCode() == key2.hashCode() }
val m = mutableMapOf<KDF.Instance, String>()
m[key1] = "foo"
m[key2] = "bar"
m[key3] = "foobar"
assertEquals("bar", m[key1])
assertEquals("bar", m[key2])
assertEquals("foobar", m[key3])
val set1 = setOf(key1, key2, key3)
val set2 = setOf(key3, key2, key1)
assertEquals(set2, set1)
}
@Test
fun complexityTest() = runTest{
initCrypto()
val kk = KDF.Complexity.Interactive.kdfForSize(3).deriveMultipleKeys("lala", 3)
assertEquals(3, kk.size)
}
@Test
fun complexityKdfForSizeInBytesTest() = runTest {
initCrypto()
val size = KDF.Argon.minKeySize + 17
val expectedSalt = UByteArray(KDF.Argon.saltSize) { (it + 3).toUByte() }
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)
}
@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
fun deriveFromBytesTest() = runTest {
initCrypto()
val salt = UByteArray(KDF.Argon.saltSize) { it.toUByte() }
val kdf = KDF.Argon.create(KDF.Complexity.Interactive, salt, 80)
val source = UByteArray(47) { (it * 3).toUByte() }
val b1 = kdf.deriveFromBytes(source)
val b2 = kdf.deriveFromBytes(source)
val b3 = kdf.deriveFromBytes(source + 1u)
assertEquals(80, b1.size)
assertContentEquals(b1, b2)
assertFalse { b1 contentEquals b3 }
}
@Test
fun complexityDeriveFromBytesTest() = runTest {
initCrypto()
val salt = UByteArray(KDF.Argon.saltSize) { (it + 1).toUByte() }
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)
assertContentEquals(b1, b2)
assertEquals(64, b1.size)
}
@Test
fun deriveFromBytesUsesKeySizeTest() = runTest {
initCrypto()
val salt = UByteArray(KDF.Argon.saltSize) { it.toUByte() }
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)
assertEquals(64, shortKdf.deriveFromBytes(source).size)
assertEquals(96, longKdf.deriveFromBytes(source).size)
}
}