diff --git a/README.md b/README.md index 6451fc3..dbe69e1 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ repositories { maven("https://gitea.sergeych.net/api/packages/SergeychWorks/maven") } dependencies { - import("net.sergeych:crypto2:0.5.6") + import("net.sergeych:crypto2:0.5.7") } ``` diff --git a/build.gradle.kts b/build.gradle.kts index 0497bb8..3a9be63 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ plugins { } group = "net.sergeych" -version = "0.5.6" +version = "0.5.7" repositories { mavenCentral() diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/kdf.kt b/src/commonMain/kotlin/net/sergeych/crypto2/kdf.kt index 46c6ef1..7deadf4 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/kdf.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/kdf.kt @@ -4,25 +4,39 @@ import com.ionspin.kotlin.crypto.pwhash.* import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import net.sergeych.bipack.Unsigned +import net.sergeych.crypto2.KDF.Argon.Alg.V2id_13 +import net.sergeych.crypto2.KDF.Complexity.* import net.sergeych.crypto2.PBKD.Params @Serializable sealed class KDF { + /** + * KDF complexity: how many resources (CPY and RAM) it requires to transform a string to a key. + * + * Constants started with `Fixed...`, e.g., [FixedLow], [FixedMedium] and [FixedHigher] + * are first clas constants not to be changed in future but can become obsolete (too simple) with the + * development of the computer hardware. Other constants can change in future releases, so it is critical + * to serialize [KDF] or [PBKD.Params] generated with such constants and restore them before + * deriving keys. + */ enum class Complexity { + FixedLow, Interactive, + FixedMedium, Moderate, + FixedHigher, Sensitive, } abstract fun derive(password: String): UByteArray - fun deriveMultiple(password: String,count: Int) : List { + fun deriveMultiple(password: String, count: Int): List { val bytes = derive(password) val ks = SymmetricKey.keyLength - check( ks * count <= bytes.size ) { "KDF is too short for $count keys: ${bytes.size} we need ${ks*count}"} - return (0 ..< count).map { - val base = it*ks + check(ks * count <= bytes.size) { "KDF is too short for $count keys: ${bytes.size} we need ${ks * count}" } + return (0.. minKeySize) { "The key size should be at least $keySize bytes" } return when (complexity) { - Complexity.Interactive -> Argon( + FixedLow -> Argon( + V2id_13, + 2UL, + 67108864, + salt, keySize + ) + + Interactive -> Argon( Alg.default, crypto_pwhash_OPSLIMIT_INTERACTIVE.toULong(), crypto_pwhash_MEMLIMIT_INTERACTIVE, salt, keySize ) - Complexity.Moderate -> Argon( + FixedMedium -> Argon( + V2id_13, + 3UL, + 268435456, + salt, keySize + ) + Moderate -> Argon( Alg.default, crypto_pwhash_OPSLIMIT_MODERATE, crypto_pwhash_MEMLIMIT_MODERATE, @@ -120,6 +148,14 @@ sealed class KDF { crypto_pwhash_MEMLIMIT_SENSITIVE, salt, keySize ) + + Complexity.FixedHigher -> Argon( + V2id_13, + 4UL, + 1073741824, + salt, keySize + ) + } } } @@ -128,11 +164,11 @@ sealed class KDF { companion object { @Suppress("unused") fun creteDefault(keySize: Int, complexity: Complexity, salt: UByteArray = Argon.randomSalt()): KDF { - return Argon.create(complexity,salt,keySize) + return Argon.create(complexity, salt, keySize) } } - data class Instance(val kdf: KDF,val password: String) + data class Instance(val kdf: KDF, val password: String) }