PBKD semi ready, before key refactoring

This commit is contained in:
Sergey Chernov 2024-06-24 15:01:42 +07:00
parent 2cd4eaccab
commit 5c97e857fc
2 changed files with 39 additions and 23 deletions

View File

@ -2,7 +2,6 @@ package net.sergeych.crypto2
import com.ionspin.kotlin.crypto.util.encodeToUByteArray
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import net.sergeych.bipack.BipackEncoder
import net.sergeych.bipack.Unsigned
import net.sergeych.synctools.ProtectedOp
@ -10,17 +9,31 @@ import net.sergeych.synctools.invoke
object PBKD {
/**
* Parameters to generate a reasonably secure data bytes with [deriveUBytes] or a [SymmetricKey]
* with [deriveKey]
*/
@Serializable
class Params(
val kdf: KDF,
@Unsigned
val startOffset: Int,
@Transient
private var precalculatedKey: SymmetricKey?=null
@Unsigned
val length: Int,
) {
/**
* Derive a key from the password in the idempotent manner.
* Derive UByteArray from the password in the idempotent way.
* Could be used to construct keys, IVs, tokens, whatever.
* Most often [deriveKey] is used instead which derives the key.
*/
fun deriveUBytes(password: String): UByteArray {
val bytes = generate(kdf, password)
return bytes.sliceArray(startOffset..<startOffset + length)
}
/**
* Derive a new key from the password in the idempotent manner.
* If the [keyId] is provided, it will be used to determine key type (otherwise default asymmetric)
* and to check the result, and the exception will be thrown.
*
@ -31,10 +44,7 @@ object PBKD {
* @param keyId optional key id, to get a key type from and check the result
* @throws IncorrectPasswordException if [keyId] is provided and does not match the derivation result
*/
fun derive(password: String, keyId: KeyId? = null): SymmetricKey {
// could be already calculated
precalculatedKey?.let { return it }
fun deriveKey(password: String, keyId: KeyId? = null): SymmetricKey {
// check key id sanity
keyId?.let {
if (it.id.magick != KeysMagickNumber.defaultSymmetric.number) {
@ -42,28 +52,36 @@ object PBKD {
}
}
// this will not be ok when we support other key types:
val keySize = SymmetricKey.keyLength
if (SymmetricKey.keyLength != length)
throw NotSupportedException("can't create key from $length byte(s), required ${SymmetricKey.keyLength}")
// derive
val bytes = generate(kdf, password)
val key = SymmetricKey(bytes.sliceArray(startOffset..<startOffset + keySize), this)
val key = SymmetricKey(
deriveUBytes(password)
.sliceArray(startOffset..<startOffset + SymmetricKey.keyLength),
this
)
// check if we can checking
if( keyId != null && keyId != key.id )
// check if we can
if (keyId != null && keyId != key.id)
throw IncorrectPasswordException()
// save for later
precalculatedKey = key
return key
}
}
/**
* Create [PBKD.Params] to derive several keys from the single password
* Derive several keys-suitable params
*/
fun createMutlipleParams(complexity: KDF.Complexity,keysCount: Int): List<Params> {
TODO()
fun deriveMultipleKeys(password: String,keysCount: Int,
complexity: KDF.Complexity = KDF.Complexity.Moderate,
salt: UByteArray = KDF.Argon.randomSalt()
): List<SymmetricKey> {
require(keysCount > 0) { "keysCount must be positive" }
val keyLength = SymmetricKey.keyLength
val totalSize = keysCount * keyLength
val kdf = KDF.Argon.create(complexity, salt, totalSize)
return (0 ..< keysCount).map { Params(kdf, it*keyLength, keyLength).deriveKey(password) }
}
private val op = ProtectedOp()

View File

@ -55,10 +55,8 @@ sealed class KDF {
}
}
override fun derive(password: String): UByteArray {
TODO()
//PasswordHash.pwhash(keySize, )
}
override fun derive(password: String): UByteArray =
PasswordHash.pwhash(keySize, password, salt, instructionsComplexity, memComplexity, algorithm.code)
override fun equals(other: Any?): Boolean {
if (this === other) return true