Added _kdf_ all implementations and a simple and probably pointless test, also noted which functions are not available as they are not part of LazySodium

This commit is contained in:
Ugljesa Jovanovic committed 2020-09-16 14:09:14 +02:00
1 parent 5c387545ab
commit 8b26764938
7 files changed
+262 -29

No files matched your search

@@ -0,0 +1,33 @@
package com.ionspin.kotlin.crypto.kdf
/**
* Created by Ugljesa Jovanovic (jovanovic.ugljesa@gmail.com) on 16/Sep/2020
*/
const val crypto_kdf_PRIMITIVE = "blake2b"
const val crypto_kdf_BYTES_MIN = 16
const val crypto_kdf_BYTES_MAX = 64
const val crypto_kdf_CONTEXTBYTES = 8
const val crypto_kdf_KEYBYTES = 32
expect object Kdf {
/**
* The crypto_kdf_derive_from_key() function derives a subkey_id-th subkey subkey of length subkey_len bytes using
* the master key key and the context ctx.
* subkey_id can be any value up to (2^64)-1.
* subkey_len has to be between crypto_kdf_BYTES_MIN (inclusive) and crypto_kdf_BYTES_MAX (inclusive).
* Similar to a type, the context ctx is a 8 characters string describing what the key is going to be used for.
* Its purpose is to mitigate accidental bugs by separating domains. The same function used with the same key but
* in two distinct contexts is likely to generate two different outputs.
* Contexts don't have to be secret and can have a low entropy.
* Examples of contexts include UserName, __auth__, pictures and userdata.
* They must be crypto_kdf_CONTEXTBYTES bytes long.
* If more convenient, it is also fine to use a single global context for a whole application. This will still
* prevent the same keys from being mistakenly used by another application.
*/
fun deriveFromKey(subkeyId: Int, subkeyLength: Int, context: String, masterKey: UByteArray) : UByteArray
/**
* The crypto_kdf_keygen() function creates a master key.
*/
fun keygen() : UByteArray
}
@@ -0,0 +1,34 @@
package com.ionspin.kotlin.crypto.kdf
import com.ionspin.kotlin.crypto.LibsodiumInitializer
import kotlin.test.Test
import kotlin.test.assertFails
import kotlin.test.assertFalse
import kotlin.test.assertTrue
/**
* Created by Ugljesa Jovanovic (jovanovic.ugljesa@gmail.com) on 16/Sep/2020
*/
class KdfTest {
@Test
fun testKdf() {
LibsodiumInitializer.initializeWithCallback {
val masterKey = Kdf.keygen()
val subkey1 = Kdf.deriveFromKey(1, crypto_kdf_BYTES_MAX, "test1234", masterKey)
val subkey2 = Kdf.deriveFromKey(2, crypto_kdf_BYTES_MAX, "test1234", masterKey)
assertTrue {
subkey1.size == crypto_kdf_BYTES_MAX &&
subkey2.size == crypto_kdf_BYTES_MAX
}
val repeatSubkey1 = Kdf.deriveFromKey(1, crypto_kdf_BYTES_MAX, "test1234", masterKey)
assertTrue {
subkey1.contentEquals(repeatSubkey1)
}
assertFalse {
subkey1.contentEquals(subkey2)
}
}
}
}
@@ -174,7 +174,15 @@ interface JsSodiumInterface {
fun crypto_sign_verify_detached(signature: Uint8Array, message: Uint8Array, publicKey: Uint8Array) : Boolean
// ---- Sign end
// ---- Sign end ----
// ---- KDF ----
fun crypto_kdf_derive_from_key(subkey_len: UInt, subkeyId : UInt, ctx: String, key: Uint8Array) : Uint8Array
fun crypto_kdf_keygen() : Uint8Array
// ---- KDF end -----
//util
fun memzero(array: Uint8Array)
@@ -0,0 +1,43 @@
package com.ionspin.kotlin.crypto.kdf
import com.ionspin.kotlin.crypto.getSodium
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
actual object Kdf {
/**
* The crypto_kdf_derive_from_key() function derives a subkey_id-th subkey subkey of length subkey_len bytes using
* the master key key and the context ctx.
* subkey_id can be any value up to (2^64)-1.
* subkey_len has to be between crypto_kdf_BYTES_MIN (inclusive) and crypto_kdf_BYTES_MAX (inclusive).
* Similar to a type, the context ctx is a 8 characters string describing what the key is going to be used for.
* Its purpose is to mitigate accidental bugs by separating domains. The same function used with the same key but
* in two distinct contexts is likely to generate two different outputs.
* Contexts don't have to be secret and can have a low entropy.
* Examples of contexts include UserName, __auth__, pictures and userdata.
* They must be crypto_kdf_CONTEXTBYTES bytes long.
* If more convenient, it is also fine to use a single global context for a whole application. This will still
* prevent the same keys from being mistakenly used by another application.
*/
actual fun deriveFromKey(
subkeyId: Int,
subkeyLength: Int,
context: String,
masterKey: UByteArray
): UByteArray {
return getSodium().crypto_kdf_derive_from_key(
subkeyLength.toUInt(),
subkeyId.toUInt(),
context,
masterKey.toUInt8Array()
).toUByteArray()
}
/**
* The crypto_kdf_keygen() function creates a master key.
*/
actual fun keygen(): UByteArray {
return getSodium().crypto_kdf_keygen().toUByteArray()
}
}
@@ -0,0 +1,49 @@
package com.ionspin.kotlin.crypto.kdf
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodium
actual object Kdf {
/**
* The crypto_kdf_derive_from_key() function derives a subkey_id-th subkey subkey of length subkey_len bytes using
* the master key key and the context ctx.
* subkey_id can be any value up to (2^64)-1.
* subkey_len has to be between crypto_kdf_BYTES_MIN (inclusive) and crypto_kdf_BYTES_MAX (inclusive).
* Similar to a type, the context ctx is a 8 characters string describing what the key is going to be used for.
* Its purpose is to mitigate accidental bugs by separating domains. The same function used with the same key but
* in two distinct contexts is likely to generate two different outputs.
* Contexts don't have to be secret and can have a low entropy.
* Examples of contexts include UserName, __auth__, pictures and userdata.
* They must be crypto_kdf_CONTEXTBYTES bytes long.
* If more convenient, it is also fine to use a single global context for a whole application. This will still
* prevent the same keys from being mistakenly used by another application.
*/
actual fun deriveFromKey(
subkeyId: Int,
subkeyLength: Int,
context: String,
masterKey: UByteArray
): UByteArray {
val subkey = UByteArray(subkeyLength)
val contextEncoded = context.encodeToByteArray()
sodium.crypto_kdf_derive_from_key(
subkey.asByteArray(),
subkeyLength,
subkeyId.toLong(),
contextEncoded,
masterKey.asByteArray()
)
return subkey
}
/**
* The crypto_kdf_keygen() function creates a master key.
*/
actual fun keygen(): UByteArray {
val masterKey = UByteArray(crypto_kdf_KEYBYTES)
sodium.crypto_kdf_keygen(masterKey.asByteArray())
return masterKey
}
}
@@ -0,0 +1,66 @@
package com.ionspin.kotlin.crypto.kdf
import com.ionspin.kotlin.crypto.util.encodeToUByteArray
import com.ionspin.kotlin.crypto.util.toPtr
import kotlinx.cinterop.addressOf
import kotlinx.cinterop.convert
import kotlinx.cinterop.pin
import libsodium.crypto_kdf_derive_from_key
import libsodium.crypto_kdf_keygen
actual object Kdf {
/**
* The crypto_kdf_derive_from_key() function derives a subkey_id-th subkey subkey of length subkey_len bytes using
* the master key key and the context ctx.
* subkey_id can be any value up to (2^64)-1.
* subkey_len has to be between crypto_kdf_BYTES_MIN (inclusive) and crypto_kdf_BYTES_MAX (inclusive).
* Similar to a type, the context ctx is a 8 characters string describing what the key is going to be used for.
* Its purpose is to mitigate accidental bugs by separating domains. The same function used with the same key but
* in two distinct contexts is likely to generate two different outputs.
* Contexts don't have to be secret and can have a low entropy.
* Examples of contexts include UserName, __auth__, pictures and userdata.
* They must be crypto_kdf_CONTEXTBYTES bytes long.
* If more convenient, it is also fine to use a single global context for a whole application. This will still
* prevent the same keys from being mistakenly used by another application.
*/
actual fun deriveFromKey(
subkeyId: Int,
subkeyLength: Int,
context: String,
masterKey: UByteArray
): UByteArray {
val subkey = UByteArray(subkeyLength)
val contextEncoded = context.encodeToByteArray()
val contextEncodedAndPinned = contextEncoded.pin()
val masterKeyPinned = masterKey.pin()
val subkeyPinned = subkey.pin()
crypto_kdf_derive_from_key(
subkeyPinned.toPtr(),
subkeyLength.convert(),
subkeyId.convert(),
contextEncodedAndPinned.addressOf(0),
masterKeyPinned.toPtr()
)
contextEncodedAndPinned.unpin()
masterKeyPinned.unpin()
subkeyPinned.unpin()
return subkey
}
/**
* The crypto_kdf_keygen() function creates a master key.
*/
actual fun keygen(): UByteArray {
val masterKey = UByteArray(crypto_kdf_KEYBYTES)
val masterKeyPinned = masterKey.pin()
crypto_kdf_keygen(masterKeyPinned.toPtr())
masterKeyPinned.unpin()
return masterKey
}
}