+KDF derive from bytes
This commit is contained in:
parent
d0f1fffe6d
commit
5c3ff72123
@ -66,6 +66,12 @@ sealed class KDF {
|
||||
* Derive single key from password, same as [deriveMultiple] with count=1.
|
||||
*/
|
||||
fun derive(password: String, salt: UByteArray): SymmetricKey = deriveMultiple(password, 1, salt).first()
|
||||
|
||||
/**
|
||||
* Derive bytes from bytes using the default [Argon] KDF with this complexity.
|
||||
*/
|
||||
fun derive(source: UByteArray, salt: UByteArray, derivedSize: Int): UByteArray =
|
||||
creteDefault(derivedSize, this, salt).deriveFromBytes(source, derivedSize)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,6 +79,11 @@ sealed class KDF {
|
||||
*/
|
||||
abstract fun deriveKey(password: String): UByteArray
|
||||
|
||||
/**
|
||||
* Derive bytes from bytes using this KDF parameters.
|
||||
*/
|
||||
abstract fun deriveFromBytes(source: UByteArray, derivedSize: Int): UByteArray
|
||||
|
||||
/**
|
||||
* Derive keys from lower part of bytes derived from the password. E.g., if generated size is longer than
|
||||
* required to create [count] keys, the first bytes will be used. It let use rest bytes for other purposes.
|
||||
@ -131,6 +142,18 @@ sealed class KDF {
|
||||
override fun deriveKey(password: String): UByteArray =
|
||||
PasswordHash.pwhash(keySize, password, salt, instructionsComplexity, memComplexity, algorithm.code)
|
||||
|
||||
override fun deriveFromBytes(source: UByteArray, derivedSize: Int): UByteArray {
|
||||
require(derivedSize >= minKeySize) { "The derived size should be at least $minKeySize bytes" }
|
||||
return PasswordHash.pwhash(
|
||||
derivedSize,
|
||||
source.encodeToBase64Url(),
|
||||
salt,
|
||||
instructionsComplexity,
|
||||
memComplexity,
|
||||
algorithm.code
|
||||
)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is Argon) return false
|
||||
@ -171,7 +194,7 @@ sealed class KDF {
|
||||
|
||||
fun create(complexity: Complexity, salt: UByteArray, keySize: Int): Argon {
|
||||
require(salt.size == saltSize) { "The salt size should be $saltSize" }
|
||||
require(keySize > minKeySize) { "The key size should be at least $keySize bytes" }
|
||||
require(keySize >= minKeySize) { "The key size should be at least $minKeySize bytes" }
|
||||
return when (complexity) {
|
||||
FixedLow -> Argon(
|
||||
V2id_13,
|
||||
@ -221,6 +244,7 @@ sealed class KDF {
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun creteDefault(keySize: Int, complexity: Complexity, salt: UByteArray = Argon.randomSalt()): KDF {
|
||||
return Argon.create(complexity, salt, keySize)
|
||||
}
|
||||
@ -230,4 +254,3 @@ sealed class KDF {
|
||||
data class Instance(val kdf: KDF, val password: String)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -12,8 +12,10 @@ import kotlinx.coroutines.test.runTest
|
||||
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.assertFailsWith
|
||||
|
||||
class KDFTest {
|
||||
@Test
|
||||
@ -55,4 +57,44 @@ class KDFTest {
|
||||
assertEquals(3, kk.size)
|
||||
}
|
||||
|
||||
}
|
||||
@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, 80)
|
||||
val b2 = kdf.deriveFromBytes(source, 80)
|
||||
val b3 = kdf.deriveFromBytes(source + 1u, 80)
|
||||
|
||||
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, 64)
|
||||
|
||||
assertContentEquals(b1, b2)
|
||||
assertEquals(64, b1.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deriveFromBytesValidationTest() = runTest {
|
||||
initCrypto()
|
||||
val salt = UByteArray(KDF.Argon.saltSize) { it.toUByte() }
|
||||
val kdf = KDF.Argon.create(KDF.Complexity.Interactive, salt, KDF.Argon.minKeySize)
|
||||
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
kdf.deriveFromBytes(ubyteArrayOf(1u, 2u, 3u), KDF.Argon.minKeySize - 1)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user