+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.
|
* Derive single key from password, same as [deriveMultiple] with count=1.
|
||||||
*/
|
*/
|
||||||
fun derive(password: String, salt: UByteArray): SymmetricKey = deriveMultiple(password, 1, salt).first()
|
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
|
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
|
* 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.
|
* 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 =
|
override fun deriveKey(password: String): UByteArray =
|
||||||
PasswordHash.pwhash(keySize, password, salt, instructionsComplexity, memComplexity, algorithm.code)
|
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 {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (other !is Argon) return false
|
if (other !is Argon) return false
|
||||||
@ -171,7 +194,7 @@ sealed class KDF {
|
|||||||
|
|
||||||
fun create(complexity: Complexity, salt: UByteArray, keySize: Int): Argon {
|
fun create(complexity: Complexity, salt: UByteArray, keySize: Int): Argon {
|
||||||
require(salt.size == saltSize) { "The salt size should be $saltSize" }
|
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) {
|
return when (complexity) {
|
||||||
FixedLow -> Argon(
|
FixedLow -> Argon(
|
||||||
V2id_13,
|
V2id_13,
|
||||||
@ -221,6 +244,7 @@ sealed class KDF {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun creteDefault(keySize: Int, complexity: Complexity, salt: UByteArray = Argon.randomSalt()): KDF {
|
fun creteDefault(keySize: Int, complexity: Complexity, salt: UByteArray = Argon.randomSalt()): KDF {
|
||||||
return Argon.create(complexity, salt, keySize)
|
return Argon.create(complexity, salt, keySize)
|
||||||
}
|
}
|
||||||
@ -230,4 +254,3 @@ sealed class KDF {
|
|||||||
data class Instance(val kdf: KDF, val password: String)
|
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.KDF
|
||||||
import net.sergeych.crypto2.initCrypto
|
import net.sergeych.crypto2.initCrypto
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertContentEquals
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertFalse
|
import kotlin.test.assertFalse
|
||||||
|
import kotlin.test.assertFailsWith
|
||||||
|
|
||||||
class KDFTest {
|
class KDFTest {
|
||||||
@Test
|
@Test
|
||||||
@ -55,4 +57,44 @@ class KDFTest {
|
|||||||
assertEquals(3, kk.size)
|
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