/* * 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() 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) 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(shortKdf) assertIs(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) } }