Our sweet start
This commit is contained in:
parent
df86967662
commit
d26ef0d41e
@ -72,6 +72,20 @@ object Deps {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object wasmJs {
|
||||||
|
val stdLib = "stdlib-wasm"
|
||||||
|
val test = "test-wasm"
|
||||||
|
// TODO: написано от балды \/
|
||||||
|
// val coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-core-js:${Versions.kotlinCoroutines}"
|
||||||
|
// val serialization = "org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:${Versions.kotlinSerialization}"
|
||||||
|
|
||||||
|
|
||||||
|
object Npm {
|
||||||
|
val libsodiumWrappers = Pair("libsodium-wrappers-sumo", "0.7.13")
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object Jvm {
|
object Jvm {
|
||||||
val stdLib = "stdlib-jdk8"
|
val stdLib = "stdlib-jdk8"
|
||||||
val test = "test"
|
val test = "test"
|
||||||
|
@ -92,6 +92,15 @@ kotlin {
|
|||||||
runningOnLinuxx86_64 {
|
runningOnLinuxx86_64 {
|
||||||
println("Configuring Linux X86-64 targets")
|
println("Configuring Linux X86-64 targets")
|
||||||
|
|
||||||
|
wasmJs {
|
||||||
|
browser {
|
||||||
|
testTask {
|
||||||
|
useKarma {
|
||||||
|
useChromeHeadless()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
js {
|
js {
|
||||||
browser {
|
browser {
|
||||||
@ -557,6 +566,19 @@ kotlin {
|
|||||||
runningOnLinuxx86_64 {
|
runningOnLinuxx86_64 {
|
||||||
println("Configuring Linux 64 Bit source sets")
|
println("Configuring Linux 64 Bit source sets")
|
||||||
|
|
||||||
|
val wasmJsMain by getting {
|
||||||
|
// TODO: разобраться (и с test)
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin(Deps.wasmJs.stdLib))
|
||||||
|
implementation(npm(Deps.wasmJs.Npm.libsodiumWrappers.first, Deps.wasmJs.Npm.libsodiumWrappers.second))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val wasmJsTest by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin(Deps.wasmJs.test))
|
||||||
|
implementation(npm(Deps.wasmJs.Npm.libsodiumWrappers.first, Deps.wasmJs.Npm.libsodiumWrappers.second))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val jsMain by getting {
|
val jsMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -709,6 +731,14 @@ tasks {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// TODO: ваще не жс тест, помогите
|
||||||
|
val wasmJsBrowserTest by getting(KotlinJsTest::class) {
|
||||||
|
testLogging {
|
||||||
|
events("PASSED", "FAILED", "SKIPPED")
|
||||||
|
showStandardStreams = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val jsBrowserTest by getting(KotlinJsTest::class) {
|
val jsBrowserTest by getting(KotlinJsTest::class) {
|
||||||
testLogging {
|
testLogging {
|
||||||
events("PASSED", "FAILED", "SKIPPED")
|
events("PASSED", "FAILED", "SKIPPED")
|
||||||
|
@ -0,0 +1,367 @@
|
|||||||
|
package ext.libsodium.com.ionspin.kotlin.crypto
|
||||||
|
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.box.BoxKeyPair
|
||||||
|
import org.khronos.webgl.Uint8Array
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Ugljesa Jovanovic
|
||||||
|
* ugljesa.jovanovic@ionspin.com
|
||||||
|
* on 27-May-2020
|
||||||
|
*/
|
||||||
|
@JsModule("libsodium-wrappers-sumo")
|
||||||
|
@JsNonModule
|
||||||
|
external object JsSodiumInterface {
|
||||||
|
|
||||||
|
|
||||||
|
@JsName("crypto_generichash")
|
||||||
|
fun crypto_generichash(hashLength: Int, inputMessage: Uint8Array, key: Uint8Array): Uint8Array
|
||||||
|
|
||||||
|
@JsName("crypto_hash_sha256")
|
||||||
|
fun crypto_hash_sha256(message: Uint8Array): Uint8Array
|
||||||
|
|
||||||
|
@JsName("crypto_hash_sha512")
|
||||||
|
fun crypto_hash_sha512(message: Uint8Array): Uint8Array
|
||||||
|
|
||||||
|
// ---- Generic hash ---- // Updateable
|
||||||
|
|
||||||
|
@JsName("crypto_generichash_init")
|
||||||
|
fun crypto_generichash_init(key : Uint8Array, hashLength: Int) : dynamic
|
||||||
|
|
||||||
|
@JsName("crypto_generichash_update")
|
||||||
|
fun crypto_generichash_update(state: dynamic, inputMessage: Uint8Array)
|
||||||
|
|
||||||
|
@JsName("crypto_generichash_final")
|
||||||
|
fun crypto_generichash_final(state: dynamic, hashLength: Int) : Uint8Array
|
||||||
|
|
||||||
|
@JsName("crypto_generichash_keygen")
|
||||||
|
fun crypto_generichash_keygen() : Uint8Array
|
||||||
|
|
||||||
|
// ---- Generic hash end ---- // Updateable
|
||||||
|
|
||||||
|
// ---- Blake2b ----
|
||||||
|
|
||||||
|
@JsName("crypto_generichash_blake2b")
|
||||||
|
fun crypto_generichash_blake2b(hashLength: Int, inputMessage: Uint8Array, key: Uint8Array): Uint8Array
|
||||||
|
|
||||||
|
@JsName("crypto_generichash_blake2b_init")
|
||||||
|
fun crypto_generichash_blake2b_init(key : Uint8Array, hashLength: Int) : dynamic
|
||||||
|
|
||||||
|
@JsName("crypto_generichash_blake2b_update")
|
||||||
|
fun crypto_generichash_blake2b_update(state: dynamic, inputMessage: Uint8Array)
|
||||||
|
|
||||||
|
@JsName("crypto_generichash_blake2b_final")
|
||||||
|
fun crypto_generichash_blake2b_final(state: dynamic, hashLength: Int) : Uint8Array
|
||||||
|
|
||||||
|
@JsName("crypto_generichash_blake2b_keygen")
|
||||||
|
fun crypto_generichash_blake2b_keygen() : Uint8Array
|
||||||
|
|
||||||
|
// ---- Blake2b end ----
|
||||||
|
|
||||||
|
// ---- Short hash ----
|
||||||
|
@JsName("crypto_shorthash")
|
||||||
|
fun crypto_shorthash(data : Uint8Array, key: Uint8Array) : Uint8Array
|
||||||
|
|
||||||
|
@JsName("crypto_shorthash_keygen")
|
||||||
|
fun crypto_shorthash_keygen() : Uint8Array
|
||||||
|
// ---- Short hash end ----
|
||||||
|
|
||||||
|
|
||||||
|
@JsName("crypto_hash_sha256_init")
|
||||||
|
fun crypto_hash_sha256_init() : dynamic
|
||||||
|
|
||||||
|
@JsName("crypto_hash_sha256_update")
|
||||||
|
fun crypto_hash_sha256_update(state: dynamic, message: Uint8Array)
|
||||||
|
|
||||||
|
@JsName("crypto_hash_sha256_final")
|
||||||
|
fun crypto_hash_sha256_final(state: dynamic): Uint8Array
|
||||||
|
|
||||||
|
@JsName("crypto_hash_sha512_init")
|
||||||
|
fun crypto_hash_sha512_init() : dynamic
|
||||||
|
|
||||||
|
@JsName("crypto_hash_sha512_update")
|
||||||
|
fun crypto_hash_sha512_update(state: dynamic, message: Uint8Array)
|
||||||
|
|
||||||
|
@JsName("crypto_hash_sha512_final")
|
||||||
|
fun crypto_hash_sha512_final(state: dynamic): Uint8Array
|
||||||
|
|
||||||
|
//XChaCha20Poly1305 - also in bindings
|
||||||
|
//fun crypto_aead_xchacha20poly1305_ietf_encrypt(message: Uint8Array, associatedData: Uint8Array, secretNonce: Uint8Array, nonce: Uint8Array, key: Uint8Array) : Uint8Array
|
||||||
|
//fun crypto_aead_xchacha20poly1305_ietf_decrypt(secretNonce: Uint8Array, ciphertext: Uint8Array, associatedData: Uint8Array, nonce: Uint8Array, key: Uint8Array) : Uint8Array
|
||||||
|
|
||||||
|
//XChaCha20Poly1305
|
||||||
|
//encrypt
|
||||||
|
@JsName("crypto_secretstream_xchacha20poly1305_init_push")
|
||||||
|
fun crypto_secretstream_xchacha20poly1305_init_push(key: Uint8Array) : dynamic
|
||||||
|
@JsName("crypto_secretstream_xchacha20poly1305_push")
|
||||||
|
fun crypto_secretstream_xchacha20poly1305_push(state: dynamic, message: Uint8Array, associatedData: Uint8Array, tag: UByte) : Uint8Array
|
||||||
|
|
||||||
|
//decrypt
|
||||||
|
@JsName("crypto_secretstream_xchacha20poly1305_init_pull")
|
||||||
|
fun crypto_secretstream_xchacha20poly1305_init_pull(header: Uint8Array, key: Uint8Array) : dynamic
|
||||||
|
@JsName("crypto_secretstream_xchacha20poly1305_pull")
|
||||||
|
fun crypto_secretstream_xchacha20poly1305_pull(state: dynamic, ciphertext: Uint8Array, associatedData: Uint8Array) : dynamic
|
||||||
|
|
||||||
|
//keygen and rekey
|
||||||
|
@JsName("crypto_secretstream_xchacha20poly1305_keygen")
|
||||||
|
fun crypto_secretstream_xchacha20poly1305_keygen() : Uint8Array
|
||||||
|
@JsName("crypto_secretstream_xchacha20poly1305_rekey")
|
||||||
|
fun crypto_secretstream_xchacha20poly1305_rekey(state: dynamic)
|
||||||
|
|
||||||
|
// ---- SecretBox ----
|
||||||
|
@JsName("crypto_secretbox_detached")
|
||||||
|
fun crypto_secretbox_detached(message: Uint8Array, nonce: Uint8Array, key: Uint8Array) : dynamic
|
||||||
|
@JsName("crypto_secretbox_easy")
|
||||||
|
fun crypto_secretbox_easy(message: Uint8Array, nonce: Uint8Array, key: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_secretbox_keygen")
|
||||||
|
fun crypto_secretbox_keygen() : Uint8Array
|
||||||
|
@JsName("crypto_secretbox_open_detached")
|
||||||
|
fun crypto_secretbox_open_detached(ciphertext : Uint8Array, tag : Uint8Array, nonce: Uint8Array, key: Uint8Array) : dynamic
|
||||||
|
@JsName("crypto_secretbox_open_easy")
|
||||||
|
fun crypto_secretbox_open_easy(ciphertext : Uint8Array, nonce: Uint8Array, key: Uint8Array) : dynamic
|
||||||
|
|
||||||
|
|
||||||
|
// ---- SecretBox End ----
|
||||||
|
|
||||||
|
|
||||||
|
// ---- AEAD ----
|
||||||
|
@JsName("crypto_aead_chacha20poly1305_decrypt")
|
||||||
|
fun crypto_aead_chacha20poly1305_decrypt(nsec : Uint8Array?, ciphertext: Uint8Array, associatedData: Uint8Array, npub: Uint8Array, key: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_aead_chacha20poly1305_decrypt_detached")
|
||||||
|
fun crypto_aead_chacha20poly1305_decrypt_detached(nsec: Uint8Array?, ciphertext: Uint8Array, mac: Uint8Array, associatedData: Uint8Array, npub: Uint8Array, key: Uint8Array): Uint8Array
|
||||||
|
@JsName("crypto_aead_chacha20poly1305_encrypt")
|
||||||
|
fun crypto_aead_chacha20poly1305_encrypt(message: Uint8Array, associatedData: Uint8Array, nsec: Uint8Array?, npub: Uint8Array, key: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_aead_chacha20poly1305_encrypt_detached")
|
||||||
|
fun crypto_aead_chacha20poly1305_encrypt_detached(message: Uint8Array, associatedData: Uint8Array, nsec: Uint8Array?, npub: Uint8Array, key: Uint8Array) : dynamic
|
||||||
|
@JsName("crypto_aead_chacha20poly1305_ietf_decrypt")
|
||||||
|
fun crypto_aead_chacha20poly1305_ietf_decrypt(nsec : Uint8Array?, ciphertext: Uint8Array, associatedData: Uint8Array, npub: Uint8Array, key: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_aead_chacha20poly1305_ietf_decrypt_detached")
|
||||||
|
fun crypto_aead_chacha20poly1305_ietf_decrypt_detached(nsec: Uint8Array?, ciphertext: Uint8Array, mac: Uint8Array, associatedData: Uint8Array, npub: Uint8Array, key: Uint8Array): Uint8Array
|
||||||
|
@JsName("crypto_aead_chacha20poly1305_ietf_encrypt")
|
||||||
|
fun crypto_aead_chacha20poly1305_ietf_encrypt(message: Uint8Array, associatedData: Uint8Array, nsec: Uint8Array?, npub: Uint8Array, key: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_aead_chacha20poly1305_ietf_encrypt_detached")
|
||||||
|
fun crypto_aead_chacha20poly1305_ietf_encrypt_detached(message: Uint8Array, associatedData: Uint8Array, nsec: Uint8Array?, npub: Uint8Array, key: Uint8Array) : dynamic
|
||||||
|
@JsName("crypto_aead_chacha20poly1305_ietf_keygen")
|
||||||
|
fun crypto_aead_chacha20poly1305_ietf_keygen() : Uint8Array
|
||||||
|
@JsName("crypto_aead_chacha20poly1305_keygen")
|
||||||
|
fun crypto_aead_chacha20poly1305_keygen() : Uint8Array
|
||||||
|
@JsName("crypto_aead_xchacha20poly1305_ietf_decrypt")
|
||||||
|
fun crypto_aead_xchacha20poly1305_ietf_decrypt(nsec : Uint8Array?, ciphertext: Uint8Array, associatedData: Uint8Array, npub: Uint8Array, key: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_aead_xchacha20poly1305_ietf_decrypt_detached")
|
||||||
|
fun crypto_aead_xchacha20poly1305_ietf_decrypt_detached(nsec: Uint8Array?, ciphertext: Uint8Array, mac: Uint8Array, associatedData: Uint8Array, npub: Uint8Array, key: Uint8Array): Uint8Array
|
||||||
|
@JsName("crypto_aead_xchacha20poly1305_ietf_encrypt")
|
||||||
|
fun crypto_aead_xchacha20poly1305_ietf_encrypt(message: Uint8Array, associatedData: Uint8Array, nsec: Uint8Array?, npub: Uint8Array, key: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_aead_xchacha20poly1305_ietf_encrypt_detached")
|
||||||
|
fun crypto_aead_xchacha20poly1305_ietf_encrypt_detached(message: Uint8Array, associatedData: Uint8Array, nsec: Uint8Array?, npub: Uint8Array, key: Uint8Array) : dynamic
|
||||||
|
@JsName("crypto_aead_xchacha20poly1305_ietf_keygen")
|
||||||
|
fun crypto_aead_xchacha20poly1305_ietf_keygen(): Uint8Array
|
||||||
|
|
||||||
|
// ---- AEAD end ----
|
||||||
|
|
||||||
|
// ---- Auth ----
|
||||||
|
|
||||||
|
@JsName("crypto_auth")
|
||||||
|
fun crypto_auth(message: Uint8Array, key: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_auth_keygen")
|
||||||
|
fun crypto_auth_keygen() : Uint8Array
|
||||||
|
@JsName("crypto_auth_verify")
|
||||||
|
fun crypto_auth_verify(tag: Uint8Array, message: Uint8Array, key: Uint8Array) : Boolean
|
||||||
|
@JsName("crypto_auth_hmacsha256")
|
||||||
|
fun crypto_auth_hmacsha256(message: Uint8Array, key: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_auth_hmacsha256_keygen")
|
||||||
|
fun crypto_auth_hmacsha256_keygen() : Uint8Array
|
||||||
|
@JsName("crypto_auth_hmacsha256_verify")
|
||||||
|
fun crypto_auth_hmacsha256_verify(tag: Uint8Array, message: Uint8Array, key: Uint8Array) : Boolean
|
||||||
|
@JsName("crypto_auth_hmacsha512")
|
||||||
|
fun crypto_auth_hmacsha512(message: Uint8Array, key: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_auth_hmacsha512_keygen")
|
||||||
|
fun crypto_auth_hmacsha512_keygen() : Uint8Array
|
||||||
|
@JsName("crypto_auth_hmacsha512_verify")
|
||||||
|
fun crypto_auth_hmacsha512_verify(tag: Uint8Array, message: Uint8Array, key: Uint8Array) : Boolean
|
||||||
|
|
||||||
|
// ---- Auth end ----
|
||||||
|
|
||||||
|
// ---- Box ----
|
||||||
|
|
||||||
|
@JsName("crypto_box_keypair")
|
||||||
|
fun crypto_box_keypair() : dynamic
|
||||||
|
@JsName("crypto_box_seed_keypair")
|
||||||
|
fun crypto_box_seed_keypair(seed : Uint8Array) : dynamic
|
||||||
|
@JsName("crypto_box_easy")
|
||||||
|
fun crypto_box_easy(message: Uint8Array,
|
||||||
|
nonce: Uint8Array,
|
||||||
|
recipientsPublicKey: Uint8Array,
|
||||||
|
sendersSecretKey: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_box_open_easy")
|
||||||
|
fun crypto_box_open_easy(ciphertext: Uint8Array,
|
||||||
|
nonce: Uint8Array,
|
||||||
|
sendersPublicKey: Uint8Array,
|
||||||
|
recipientsSecretKey: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_box_detached")
|
||||||
|
fun crypto_box_detached(message: Uint8Array,
|
||||||
|
nonce: Uint8Array,
|
||||||
|
recipientsPublicKey: Uint8Array,
|
||||||
|
sendersSecretKey: Uint8Array) : dynamic
|
||||||
|
@JsName("crypto_box_open_detached")
|
||||||
|
fun crypto_box_open_detached(ciphertext: Uint8Array,
|
||||||
|
tag: Uint8Array,
|
||||||
|
nonce: Uint8Array,
|
||||||
|
sendersPublicKey: Uint8Array,
|
||||||
|
recipientsSecretKey: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_box_beforenm")
|
||||||
|
fun crypto_box_beforenm(publicKey: Uint8Array, secretKey: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_box_easy_afternm")
|
||||||
|
fun crypto_box_easy_afternm(message: Uint8Array,
|
||||||
|
nonce: Uint8Array,
|
||||||
|
precomputedKey: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_box_open_easy_afternm")
|
||||||
|
fun crypto_box_open_easy_afternm(ciphertext: Uint8Array,
|
||||||
|
nonce: Uint8Array,
|
||||||
|
precomputedKey: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_box_seal")
|
||||||
|
fun crypto_box_seal(message: Uint8Array, recipientsPublicKey: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_box_seal_open")
|
||||||
|
fun crypto_box_seal_open(ciphertext: Uint8Array, recipientsPublicKey: Uint8Array, recipientsSecretKey: Uint8Array) : Uint8Array
|
||||||
|
|
||||||
|
// ---- Box end ----
|
||||||
|
|
||||||
|
// ---- Sign start ----
|
||||||
|
@JsName("crypto_sign")
|
||||||
|
fun crypto_sign(message: Uint8Array, secretKey: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_sign_detached")
|
||||||
|
fun crypto_sign_detached(message: Uint8Array, secretKey: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_sign_ed25519_pk_to_curve25519")
|
||||||
|
fun crypto_sign_ed25519_pk_to_curve25519(ed25519PublicKey: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_sign_ed25519_sk_to_curve25519")
|
||||||
|
fun crypto_sign_ed25519_sk_to_curve25519(ed25519SecretKey: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_sign_ed25519_sk_to_pk")
|
||||||
|
fun crypto_sign_ed25519_sk_to_pk(ed25519SecretKey: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_sign_ed25519_sk_to_seed")
|
||||||
|
fun crypto_sign_ed25519_sk_to_seed(ed25519SecretKey: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_sign_final_create")
|
||||||
|
fun crypto_sign_final_create(state: dynamic, secretKey: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_sign_final_verify")
|
||||||
|
fun crypto_sign_final_verify(state: dynamic, signature: Uint8Array, publicKey: Uint8Array) : Boolean
|
||||||
|
@JsName("crypto_sign_init")
|
||||||
|
fun crypto_sign_init() : dynamic
|
||||||
|
@JsName("crypto_sign_keypair")
|
||||||
|
fun crypto_sign_keypair() : dynamic
|
||||||
|
@JsName("crypto_sign_open")
|
||||||
|
fun crypto_sign_open(signedMessage: Uint8Array, publicKey: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_sign_seed_keypair")
|
||||||
|
fun crypto_sign_seed_keypair(seed: Uint8Array) : dynamic
|
||||||
|
@JsName("crypto_sign_update")
|
||||||
|
fun crypto_sign_update(state: dynamic, message: Uint8Array)
|
||||||
|
@JsName("crypto_sign_verify_detached")
|
||||||
|
fun crypto_sign_verify_detached(signature: Uint8Array, message: Uint8Array, publicKey: Uint8Array) : Boolean
|
||||||
|
|
||||||
|
|
||||||
|
// ---- Sign end ----
|
||||||
|
|
||||||
|
|
||||||
|
// ---- KDF ----
|
||||||
|
|
||||||
|
@JsName("crypto_kdf_derive_from_key")
|
||||||
|
fun crypto_kdf_derive_from_key(subkey_len: UInt, subkeyId : UInt, ctx: String, key: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_kdf_keygen")
|
||||||
|
fun crypto_kdf_keygen() : Uint8Array
|
||||||
|
|
||||||
|
// ---- KDF end -----
|
||||||
|
|
||||||
|
// ---- Password hashing ----
|
||||||
|
|
||||||
|
@JsName("crypto_pwhash")
|
||||||
|
fun crypto_pwhash(keyLength : UInt, password : Uint8Array, salt: Uint8Array, opsLimit: UInt, memLimit: UInt, algorithm: UInt) : Uint8Array
|
||||||
|
@JsName("crypto_pwhash_str")
|
||||||
|
fun crypto_pwhash_str(password: Uint8Array, opsLimit: UInt, memLimit: UInt) : String
|
||||||
|
@JsName("crypto_pwhash_str_needs_rehash")
|
||||||
|
fun crypto_pwhash_str_needs_rehash(hashedPassword: String, opsLimit: UInt, memLimit: UInt) : Boolean
|
||||||
|
@JsName("crypto_pwhash_str_verify")
|
||||||
|
fun crypto_pwhash_str_verify(hashedPassword: String, password: Uint8Array) : Boolean
|
||||||
|
|
||||||
|
|
||||||
|
// ---- Password hashing end ----
|
||||||
|
|
||||||
|
// ---- Utils ----
|
||||||
|
|
||||||
|
@JsName("memcmp")
|
||||||
|
fun memcmp(first: Uint8Array, second: Uint8Array) : Boolean
|
||||||
|
@JsName("memzero")
|
||||||
|
fun memzero(data: Uint8Array)
|
||||||
|
@JsName("pad")
|
||||||
|
fun pad(data : Uint8Array, blocksize: Int) : Uint8Array
|
||||||
|
@JsName("unpad")
|
||||||
|
fun unpad(data: Uint8Array, blocksize: Int) : Uint8Array
|
||||||
|
@JsName("to_base64")
|
||||||
|
fun to_base64(data: Uint8Array, variant: Int) : String
|
||||||
|
@JsName("to_hex")
|
||||||
|
fun to_hex(data: Uint8Array) : String
|
||||||
|
@JsName("to_string")
|
||||||
|
fun to_string(data: Uint8Array) : String
|
||||||
|
@JsName("from_base64")
|
||||||
|
fun from_base64(data: String, variant: Int): Uint8Array
|
||||||
|
@JsName("from_hex")
|
||||||
|
fun from_hex(data : String): Uint8Array
|
||||||
|
@JsName("from_string")
|
||||||
|
fun from_string(data : String): Uint8Array
|
||||||
|
|
||||||
|
// ---- > ---- Random ---- < -----
|
||||||
|
|
||||||
|
@JsName("randombytes_buf")
|
||||||
|
fun randombytes_buf(length: Int) : Uint8Array
|
||||||
|
@JsName("randombytes_buf_deterministic")
|
||||||
|
fun randombytes_buf_deterministic(length: UInt, seed : Uint8Array) : Uint8Array
|
||||||
|
@JsName("randombytes_random")
|
||||||
|
fun randombytes_random() : UInt
|
||||||
|
@JsName("randombytes_uniform")
|
||||||
|
fun randombytes_uniform(upper_bound: UInt) : UInt
|
||||||
|
|
||||||
|
// ---- Utils end ----
|
||||||
|
|
||||||
|
// ---- Key exchange ----
|
||||||
|
@JsName("crypto_kx_client_session_keys")
|
||||||
|
fun crypto_kx_client_session_keys(clientPublicKey: Uint8Array, clientSecretKey: Uint8Array, serverPublicKey: Uint8Array) : dynamic
|
||||||
|
@JsName("crypto_kx_keypair")
|
||||||
|
fun crypto_kx_keypair() : dynamic
|
||||||
|
@JsName("crypto_kx_seed_keypair")
|
||||||
|
fun crypto_kx_seed_keypair(seed: Uint8Array) : dynamic
|
||||||
|
@JsName("crypto_kx_server_session_keys")
|
||||||
|
fun crypto_kx_server_session_keys(serverPublicKey: Uint8Array, serverSecretKey: Uint8Array, clientPublicKey: Uint8Array) : dynamic
|
||||||
|
|
||||||
|
// ---- Key exchange end ----
|
||||||
|
|
||||||
|
// -- Stream ----
|
||||||
|
@JsName("crypto_stream_chacha20")
|
||||||
|
fun crypto_stream_chacha20(outLength: UInt, key: Uint8Array, nonce: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_stream_chacha20_ietf_xor")
|
||||||
|
fun crypto_stream_chacha20_ietf_xor(message : Uint8Array, nonce: Uint8Array, key: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_stream_chacha20_ietf_xor_ic")
|
||||||
|
fun crypto_stream_chacha20_ietf_xor_ic(message : Uint8Array, nonce: Uint8Array, initialCounter: UInt, key: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_stream_chacha20_keygen")
|
||||||
|
fun crypto_stream_chacha20_keygen() : Uint8Array
|
||||||
|
@JsName("crypto_stream_chacha20_xor")
|
||||||
|
fun crypto_stream_chacha20_xor(message : Uint8Array, nonce: Uint8Array, key: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_stream_chacha20_xor_ic")
|
||||||
|
fun crypto_stream_chacha20_xor_ic(message : Uint8Array, nonce: Uint8Array, initialCounter: UInt, key: Uint8Array) : Uint8Array
|
||||||
|
|
||||||
|
@JsName("crypto_stream_xchacha20_keygen")
|
||||||
|
fun crypto_stream_xchacha20_keygen() : Uint8Array
|
||||||
|
@JsName("crypto_stream_xchacha20_xor")
|
||||||
|
fun crypto_stream_xchacha20_xor(message : Uint8Array, nonce: Uint8Array, key: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_stream_xchacha20_xor_ic")
|
||||||
|
fun crypto_stream_xchacha20_xor_ic(message : Uint8Array, nonce: Uint8Array, initialCounter: UInt, key: Uint8Array) : Uint8Array
|
||||||
|
|
||||||
|
// ---- Stream end ----
|
||||||
|
|
||||||
|
// ---- Scalar multiplication ----
|
||||||
|
|
||||||
|
@JsName("crypto_scalarmult")
|
||||||
|
fun crypto_scalarmult(privateKey: Uint8Array, publicKey: Uint8Array) : Uint8Array
|
||||||
|
@JsName("crypto_scalarmult_base")
|
||||||
|
fun crypto_scalarmult_base(privateKey: Uint8Array) : Uint8Array
|
||||||
|
|
||||||
|
// ---- Scalar multiplication end ----
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
package ext.libsodium.com.ionspin.kotlin.crypto
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.getSodiumLoaded
|
||||||
|
import com.ionspin.kotlin.crypto.sodiumLoaded
|
||||||
|
import ext.libsodium._libsodiumPromise
|
||||||
|
import ext.libsodium.crypto_generichash
|
||||||
|
import ext.libsodium.crypto_hash_sha256
|
||||||
|
import ext.libsodium.crypto_hash_sha256_init
|
||||||
|
import ext.libsodium.crypto_hash_sha512
|
||||||
|
import ext.libsodium.sodium_init
|
||||||
|
import kotlin.coroutines.suspendCoroutine
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Ugljesa Jovanovic
|
||||||
|
* ugljesa.jovanovic@ionspin.com
|
||||||
|
* on 27-May-2020
|
||||||
|
*/
|
||||||
|
object JsSodiumLoader {
|
||||||
|
|
||||||
|
class _EmitJsSodiumFunction {
|
||||||
|
init {
|
||||||
|
println(::crypto_generichash)
|
||||||
|
println(::crypto_hash_sha256)
|
||||||
|
println(::crypto_hash_sha512)
|
||||||
|
println(::crypto_hash_sha256_init)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun load() = suspendCoroutine { continuation ->
|
||||||
|
if (!getSodiumLoaded()) {
|
||||||
|
_libsodiumPromise.then<dynamic> {
|
||||||
|
sodium_init()
|
||||||
|
sodiumLoaded = true
|
||||||
|
continuation.resumeWith(Result.success(Unit))
|
||||||
|
}.catch { e ->
|
||||||
|
continuation.resumeWith(Result.failure(e))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
continuation.resumeWith(Result.success(Unit))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadWithCallback(doneCallback: () -> (Unit)) {
|
||||||
|
if (!getSodiumLoaded()) {
|
||||||
|
_libsodiumPromise.then<dynamic> {
|
||||||
|
sodium_init()
|
||||||
|
sodiumLoaded = true
|
||||||
|
doneCallback.invoke()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
doneCallback.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package ext.libsodium.com.ionspin.kotlin.crypto
|
||||||
|
|
||||||
|
import org.khronos.webgl.Uint8Array
|
||||||
|
import org.khronos.webgl.get
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Ugljesa Jovanovic
|
||||||
|
* ugljesa.jovanovic@ionspin.com
|
||||||
|
* on 02-Aug-2020
|
||||||
|
*/
|
||||||
|
fun UByteArray.toUInt8Array() : Uint8Array {
|
||||||
|
val uint8Result = Uint8Array(toByteArray().toTypedArray())
|
||||||
|
return uint8Result
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun Uint8Array.toUByteArray() : UByteArray {
|
||||||
|
if (length.asDynamic() == undefined) {
|
||||||
|
println("Error")
|
||||||
|
}
|
||||||
|
val result = UByteArray(length)
|
||||||
|
for (i in 0 until length) {
|
||||||
|
result[i] = get(i).toUByte()
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package com.ionspin.kotlin.crypto
|
||||||
|
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.JsSodiumInterface
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.JsSodiumLoader
|
||||||
|
|
||||||
|
var sodiumLoaded: Boolean = false
|
||||||
|
|
||||||
|
fun getSodium() : JsSodiumInterface = JsSodiumInterface
|
||||||
|
|
||||||
|
fun getSodiumLoaded() : Boolean = sodiumLoaded
|
||||||
|
|
||||||
|
fun setSodiumLoaded(loaded: Boolean) {
|
||||||
|
sodiumLoaded = loaded
|
||||||
|
}
|
||||||
|
|
||||||
|
actual object LibsodiumInitializer {
|
||||||
|
private var isPlatformInitialized = false
|
||||||
|
|
||||||
|
actual suspend fun initialize() {
|
||||||
|
JsSodiumLoader.load()
|
||||||
|
isPlatformInitialized = true
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun initializeWithCallback(done: () -> Unit) {
|
||||||
|
JsSodiumLoader.loadWithCallback {
|
||||||
|
isPlatformInitialized = true
|
||||||
|
done()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun isInitialized(): Boolean {
|
||||||
|
return isPlatformInitialized
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,247 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.aead
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.getSodium
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
|
||||||
|
import org.khronos.webgl.Uint8Array
|
||||||
|
|
||||||
|
actual object AuthenticatedEncryptionWithAssociatedData {
|
||||||
|
|
||||||
|
// Ietf
|
||||||
|
|
||||||
|
// Original chacha20poly1305
|
||||||
|
actual fun xChaCha20Poly1305IetfEncrypt(
|
||||||
|
message: UByteArray,
|
||||||
|
associatedData: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
key: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
return getSodium().crypto_aead_xchacha20poly1305_ietf_encrypt(
|
||||||
|
message.toUInt8Array(),
|
||||||
|
associatedData.toUInt8Array(),
|
||||||
|
null,
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
key.toUInt8Array(),
|
||||||
|
).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun xChaCha20Poly1305IetfDecrypt(
|
||||||
|
ciphertextAndTag: UByteArray,
|
||||||
|
associatedData: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
key: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
try {
|
||||||
|
return getSodium().crypto_aead_xchacha20poly1305_ietf_decrypt(
|
||||||
|
null,
|
||||||
|
ciphertextAndTag.toUInt8Array(),
|
||||||
|
associatedData.toUInt8Array(),
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
key.toUInt8Array()
|
||||||
|
).toUByteArray()
|
||||||
|
} catch (error: Throwable) {
|
||||||
|
throw AeadCorrupedOrTamperedDataException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun xChaCha20Poly1305IetfEncryptDetached(
|
||||||
|
message: UByteArray,
|
||||||
|
associatedData: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
key: UByteArray
|
||||||
|
): AeadEncryptedDataAndTag {
|
||||||
|
val result = getSodium().crypto_aead_xchacha20poly1305_ietf_encrypt_detached(
|
||||||
|
message.toUInt8Array(),
|
||||||
|
associatedData.toUInt8Array(),
|
||||||
|
null,
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
key.toUInt8Array(),
|
||||||
|
)
|
||||||
|
return AeadEncryptedDataAndTag(
|
||||||
|
(result.ciphertext as Uint8Array).toUByteArray(),
|
||||||
|
(result.mac as Uint8Array).toUByteArray()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun xChaCha20Poly1305IetfDecryptDetached(
|
||||||
|
ciphertext: UByteArray,
|
||||||
|
tag: UByteArray,
|
||||||
|
associatedData: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
key: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
try {
|
||||||
|
return getSodium().crypto_aead_xchacha20poly1305_ietf_decrypt_detached(
|
||||||
|
null,
|
||||||
|
ciphertext.toUInt8Array(),
|
||||||
|
tag.toUInt8Array(),
|
||||||
|
associatedData.toUInt8Array(),
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
key.toUInt8Array()
|
||||||
|
).toUByteArray()
|
||||||
|
} catch (error: Throwable) {
|
||||||
|
throw AeadCorrupedOrTamperedDataException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun chaCha20Poly1305IetfEncrypt(
|
||||||
|
message: UByteArray,
|
||||||
|
associatedData: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
key: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
return getSodium().crypto_aead_chacha20poly1305_ietf_encrypt(
|
||||||
|
message.toUInt8Array(),
|
||||||
|
associatedData.toUInt8Array(),
|
||||||
|
null,
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
key.toUInt8Array(),
|
||||||
|
).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun chaCha20Poly1305IetfDecrypt(
|
||||||
|
ciphertextAndTag: UByteArray,
|
||||||
|
associatedData: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
key: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
try {
|
||||||
|
return getSodium().crypto_aead_chacha20poly1305_ietf_decrypt(
|
||||||
|
null,
|
||||||
|
ciphertextAndTag.toUInt8Array(),
|
||||||
|
associatedData.toUInt8Array(),
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
key.toUInt8Array()
|
||||||
|
).toUByteArray()
|
||||||
|
} catch (error: Throwable) {
|
||||||
|
throw AeadCorrupedOrTamperedDataException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun chaCha20Poly1305IetfEncryptDetached(
|
||||||
|
message: UByteArray,
|
||||||
|
associatedData: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
key: UByteArray
|
||||||
|
): AeadEncryptedDataAndTag {
|
||||||
|
val result = getSodium().crypto_aead_chacha20poly1305_ietf_encrypt_detached(
|
||||||
|
message.toUInt8Array(),
|
||||||
|
associatedData.toUInt8Array(),
|
||||||
|
null,
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
key.toUInt8Array(),
|
||||||
|
)
|
||||||
|
return AeadEncryptedDataAndTag(
|
||||||
|
(result.ciphertext as Uint8Array).toUByteArray(),
|
||||||
|
(result.mac as Uint8Array).toUByteArray()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun chaCha20Poly1305IetfDecryptDetached(
|
||||||
|
ciphertext: UByteArray,
|
||||||
|
tag: UByteArray,
|
||||||
|
associatedData: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
key: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
try {
|
||||||
|
return getSodium().crypto_aead_chacha20poly1305_ietf_decrypt_detached(
|
||||||
|
null,
|
||||||
|
ciphertext.toUInt8Array(),
|
||||||
|
tag.toUInt8Array(),
|
||||||
|
associatedData.toUInt8Array(),
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
key.toUInt8Array()
|
||||||
|
).toUByteArray()
|
||||||
|
} catch (error: Throwable) {
|
||||||
|
throw AeadCorrupedOrTamperedDataException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun chaCha20Poly1305Encrypt(
|
||||||
|
message: UByteArray,
|
||||||
|
associatedData: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
key: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
return getSodium().crypto_aead_chacha20poly1305_encrypt(
|
||||||
|
message.toUInt8Array(),
|
||||||
|
associatedData.toUInt8Array(),
|
||||||
|
null,
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
key.toUInt8Array(),
|
||||||
|
).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun chaCha20Poly1305Decrypt(
|
||||||
|
ciphertextAndTag: UByteArray,
|
||||||
|
associatedData: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
key: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
try {
|
||||||
|
return getSodium().crypto_aead_chacha20poly1305_decrypt(
|
||||||
|
null,
|
||||||
|
ciphertextAndTag.toUInt8Array(),
|
||||||
|
associatedData.toUInt8Array(),
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
key.toUInt8Array()
|
||||||
|
).toUByteArray()
|
||||||
|
} catch (error: Throwable) {
|
||||||
|
throw AeadCorrupedOrTamperedDataException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun chaCha20Poly1305EncryptDetached(
|
||||||
|
message: UByteArray,
|
||||||
|
associatedData: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
key: UByteArray
|
||||||
|
): AeadEncryptedDataAndTag {
|
||||||
|
val result = getSodium().crypto_aead_chacha20poly1305_encrypt_detached(
|
||||||
|
message.toUInt8Array(),
|
||||||
|
associatedData.toUInt8Array(),
|
||||||
|
null,
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
key.toUInt8Array(),
|
||||||
|
)
|
||||||
|
return AeadEncryptedDataAndTag(
|
||||||
|
(result.ciphertext as Uint8Array).toUByteArray(),
|
||||||
|
(result.mac as Uint8Array).toUByteArray()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun chaCha20Poly1305DecryptDetached(
|
||||||
|
ciphertext: UByteArray,
|
||||||
|
tag: UByteArray,
|
||||||
|
associatedData: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
key: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
try {
|
||||||
|
return getSodium().crypto_aead_chacha20poly1305_decrypt_detached(
|
||||||
|
null,
|
||||||
|
ciphertext.toUInt8Array(),
|
||||||
|
tag.toUInt8Array(),
|
||||||
|
associatedData.toUInt8Array(),
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
key.toUInt8Array()
|
||||||
|
).toUByteArray()
|
||||||
|
} catch (error: Throwable) {
|
||||||
|
throw AeadCorrupedOrTamperedDataException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun xChaCha20Poly1305IetfKeygen(): UByteArray {
|
||||||
|
return getSodium().crypto_aead_xchacha20poly1305_ietf_keygen().toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun chaCha20Poly1305IetfKeygen(): UByteArray {
|
||||||
|
return getSodium().crypto_aead_chacha20poly1305_ietf_keygen().toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun chaCha20Poly1305Keygen(): UByteArray {
|
||||||
|
return getSodium().crypto_aead_chacha20poly1305_keygen().toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.auth
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.getSodium
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
|
||||||
|
|
||||||
|
actual object Auth {
|
||||||
|
actual fun authKeygen(): UByteArray {
|
||||||
|
return getSodium().crypto_auth_keygen().toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun auth(message: UByteArray, key: UByteArray): UByteArray {
|
||||||
|
return getSodium().crypto_auth(
|
||||||
|
message.toUInt8Array(),
|
||||||
|
key.toUInt8Array()
|
||||||
|
).toUByteArray()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun authVerify(tag: UByteArray, message: UByteArray, key: UByteArray): Boolean {
|
||||||
|
return getSodium().crypto_auth_verify(
|
||||||
|
tag.toUInt8Array(),
|
||||||
|
message.toUInt8Array(),
|
||||||
|
key.toUInt8Array()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun authHmacSha256Keygen(): UByteArray {
|
||||||
|
return getSodium().crypto_auth_hmacsha256_keygen().toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun authHmacSha256(message: UByteArray, key: UByteArray): UByteArray {
|
||||||
|
return getSodium().crypto_auth_hmacsha256(
|
||||||
|
message.toUInt8Array(),
|
||||||
|
key.toUInt8Array()
|
||||||
|
).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun authHmacSha256Verify(
|
||||||
|
tag: UByteArray,
|
||||||
|
message: UByteArray,
|
||||||
|
key: UByteArray
|
||||||
|
): Boolean {
|
||||||
|
return getSodium().crypto_auth_hmacsha256_verify(
|
||||||
|
tag.toUInt8Array(),
|
||||||
|
message.toUInt8Array(),
|
||||||
|
key.toUInt8Array()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun authHmacSha512Keygen(): UByteArray {
|
||||||
|
return getSodium().crypto_auth_hmacsha512_keygen().toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun authHmacSha512(message: UByteArray, key: UByteArray): UByteArray {
|
||||||
|
return getSodium().crypto_auth_hmacsha512(
|
||||||
|
message.toUInt8Array(),
|
||||||
|
key.toUInt8Array()
|
||||||
|
).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun authHmacSha512Verify(
|
||||||
|
tag: UByteArray,
|
||||||
|
message: UByteArray,
|
||||||
|
key: UByteArray
|
||||||
|
): Boolean {
|
||||||
|
return getSodium().crypto_auth_hmacsha512_verify(
|
||||||
|
tag.toUInt8Array(),
|
||||||
|
message.toUInt8Array(),
|
||||||
|
key.toUInt8Array()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,200 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.box
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.getSodium
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
|
||||||
|
import org.khronos.webgl.Uint8Array
|
||||||
|
|
||||||
|
actual object Box {
|
||||||
|
/**
|
||||||
|
* The crypto_box_keypair() function randomly generates a secret key and a corresponding public key.
|
||||||
|
* The public key is put into pk (crypto_box_PUBLICKEYBYTES bytes) and the secret key into
|
||||||
|
* sk (crypto_box_SECRETKEYBYTES bytes).
|
||||||
|
*/
|
||||||
|
actual fun keypair(): BoxKeyPair {
|
||||||
|
val keypair = getSodium().crypto_box_keypair()
|
||||||
|
return BoxKeyPair(
|
||||||
|
(keypair.publicKey as Uint8Array).toUByteArray(),
|
||||||
|
(keypair.privateKey as Uint8Array).toUByteArray()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Using crypto_box_seed_keypair(), the key pair can also be deterministically derived from a single key seed (crypto_box_SEEDBYTES bytes).
|
||||||
|
*/
|
||||||
|
actual fun seedKeypair(seed: UByteArray): BoxKeyPair {
|
||||||
|
val keypair = getSodium().crypto_box_seed_keypair(seed.toUInt8Array())
|
||||||
|
return BoxKeyPair(
|
||||||
|
(keypair.publicKey as Uint8Array).toUByteArray(),
|
||||||
|
(keypair.privateKey as Uint8Array).toUByteArray()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The crypto_box_easy() function encrypts a message m whose length is mlen bytes, with a recipient's public key pk, a sender's secret key sk and a nonce n.
|
||||||
|
* n should be crypto_box_NONCEBYTES bytes.
|
||||||
|
* c should be at least crypto_box_MACBYTES + mlen bytes long.
|
||||||
|
* This function writes the authentication tag, whose length is crypto_box_MACBYTES bytes, in c,
|
||||||
|
* immediately followed by the encrypted message, whose length is the same as the plaintext: mlen.
|
||||||
|
*/
|
||||||
|
actual fun easy(
|
||||||
|
message: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
recipientsPublicKey: UByteArray,
|
||||||
|
sendersSecretKey: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
return getSodium().crypto_box_easy(
|
||||||
|
message.toUInt8Array(),
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
recipientsPublicKey.toUInt8Array(),
|
||||||
|
sendersSecretKey.toUInt8Array(),
|
||||||
|
).toUByteArray()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The crypto_box_open_easy() function verifies and decrypts a ciphertext produced by crypto_box_easy().
|
||||||
|
* c is a pointer to an authentication tag + encrypted message combination, as produced by crypto_box_easy(). clen is the length of this authentication tag + encrypted message combination. Put differently, clen is the number of bytes written by crypto_box_easy(), which is crypto_box_MACBYTES + the length of the message.
|
||||||
|
* The nonce n has to match the nonce used to encrypt and authenticate the message.
|
||||||
|
* pk is the public key of the sender that encrypted the message. sk is the secret key of the recipient that is willing to verify and decrypt it.
|
||||||
|
* The function throws [BoxCorruptedOrTamperedDataException] if the verification fails.
|
||||||
|
*/
|
||||||
|
actual fun openEasy(
|
||||||
|
ciphertext: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
sendersPublicKey: UByteArray,
|
||||||
|
recipientsSecretKey: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
try {
|
||||||
|
return getSodium().crypto_box_open_easy(
|
||||||
|
ciphertext.toUInt8Array(),
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
sendersPublicKey.toUInt8Array(),
|
||||||
|
recipientsSecretKey.toUInt8Array(),
|
||||||
|
).toUByteArray()
|
||||||
|
} catch (error: Throwable) {
|
||||||
|
throw BoxCorruptedOrTamperedDataException()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The crypto_box_beforenm() function computes a shared secret key given a public key pk and a secret key sk,
|
||||||
|
* and puts it into k (crypto_box_BEFORENMBYTES bytes).
|
||||||
|
*/
|
||||||
|
actual fun beforeNM(publicKey: UByteArray, secretKey: UByteArray): UByteArray {
|
||||||
|
return getSodium().crypto_box_beforenm(
|
||||||
|
publicKey.toUInt8Array(),
|
||||||
|
secretKey.toUInt8Array()
|
||||||
|
).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The _afternm variants of the previously described functions accept a precalculated shared secret key k instead of a key pair.
|
||||||
|
*/
|
||||||
|
actual fun easyAfterNM(
|
||||||
|
message: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
precomputedKey: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
return getSodium().crypto_box_easy_afternm(
|
||||||
|
message.toUInt8Array(),
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
precomputedKey.toUInt8Array()
|
||||||
|
).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The _afternm variants of the previously described functions accept a precalculated shared secret key k instead of a key pair.
|
||||||
|
*/
|
||||||
|
actual fun openEasyAfterNM(
|
||||||
|
ciphertext: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
precomputedKey: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
try {
|
||||||
|
return getSodium().crypto_box_open_easy_afternm(
|
||||||
|
ciphertext.toUInt8Array(),
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
precomputedKey.toUInt8Array(),
|
||||||
|
).toUByteArray()
|
||||||
|
} catch (error: Throwable) {
|
||||||
|
throw BoxCorruptedOrTamperedDataException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function encrypts a message m of length mlen with a nonce n and a secret key sk for a recipient whose
|
||||||
|
* public key is pk, and puts the encrypted message into c.
|
||||||
|
* Exactly mlen bytes will be put into c, since this function does not prepend the authentication tag.
|
||||||
|
* The tag, whose size is crypto_box_MACBYTES bytes, will be put into mac.
|
||||||
|
*/
|
||||||
|
actual fun detached(
|
||||||
|
message: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
recipientsPublicKey: UByteArray,
|
||||||
|
sendersSecretKey: UByteArray
|
||||||
|
): BoxEncryptedDataAndTag {
|
||||||
|
val detached = getSodium().crypto_box_detached(
|
||||||
|
message.toUInt8Array(),
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
recipientsPublicKey.toUInt8Array(),
|
||||||
|
sendersSecretKey.toUInt8Array(),
|
||||||
|
)
|
||||||
|
return BoxEncryptedDataAndTag(
|
||||||
|
(detached.ciphertext as Uint8Array).toUByteArray(),
|
||||||
|
(detached.mac as Uint8Array).toUByteArray()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The crypto_box_open_detached() function verifies and decrypts an encrypted message c whose length is clen using the recipient's secret key sk and the sender's public key pk.
|
||||||
|
* clen doesn't include the tag, so this length is the same as the plaintext.
|
||||||
|
* The plaintext is put into m after verifying that mac is a valid authentication tag for this ciphertext, with the given nonce n and key k.
|
||||||
|
* The function throws [BoxCorruptedOrTamperedDataException] if the verification fails.
|
||||||
|
*/
|
||||||
|
actual fun openDetached(
|
||||||
|
ciphertext: UByteArray,
|
||||||
|
tag: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
sendersPublicKey: UByteArray,
|
||||||
|
recipientsSecretKey: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
try {
|
||||||
|
return getSodium().crypto_box_open_detached(
|
||||||
|
ciphertext.toUInt8Array(),
|
||||||
|
tag.toUInt8Array(),
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
sendersPublicKey.toUInt8Array(),
|
||||||
|
recipientsSecretKey.toUInt8Array(),
|
||||||
|
).toUByteArray()
|
||||||
|
} catch (error: Throwable) {
|
||||||
|
throw BoxCorruptedOrTamperedDataException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun seal(message: UByteArray, recipientsPublicKey: UByteArray): UByteArray {
|
||||||
|
return getSodium().crypto_box_seal(
|
||||||
|
message.toUInt8Array(),
|
||||||
|
recipientsPublicKey.toUInt8Array()
|
||||||
|
).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun sealOpen(
|
||||||
|
ciphertext: UByteArray,
|
||||||
|
recipientsPublicKey: UByteArray,
|
||||||
|
recipientsSecretKey: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
try {
|
||||||
|
return getSodium().crypto_box_seal_open(
|
||||||
|
ciphertext.toUInt8Array(),
|
||||||
|
recipientsPublicKey.toUInt8Array(),
|
||||||
|
recipientsSecretKey.toUInt8Array(),
|
||||||
|
).toUByteArray()
|
||||||
|
} catch (error: Throwable) {
|
||||||
|
throw BoxCorruptedOrTamperedDataException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.generichash
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.getSodium
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
|
||||||
|
import org.khronos.webgl.Uint8Array
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Ugljesa Jovanovic
|
||||||
|
* ugljesa.jovanovic@ionspin.com
|
||||||
|
* on 21-Aug-2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
actual typealias GenericHashStateInternal = Any
|
||||||
|
|
||||||
|
actual object GenericHash {
|
||||||
|
actual fun genericHash(
|
||||||
|
message: UByteArray,
|
||||||
|
requestedHashLength: Int,
|
||||||
|
key: UByteArray?
|
||||||
|
): UByteArray {
|
||||||
|
return getSodium().crypto_generichash(
|
||||||
|
requestedHashLength,
|
||||||
|
message.toUInt8Array(),
|
||||||
|
key?.toUInt8Array() ?: Uint8Array(0)
|
||||||
|
).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun genericHashInit(
|
||||||
|
requestedHashLength: Int,
|
||||||
|
key: UByteArray?
|
||||||
|
): GenericHashState {
|
||||||
|
val state = getSodium().crypto_generichash_init(key?.toUInt8Array() ?: Uint8Array(0), requestedHashLength)
|
||||||
|
return GenericHashState(requestedHashLength, state)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun genericHashUpdate(
|
||||||
|
state: GenericHashState,
|
||||||
|
messagePart: UByteArray
|
||||||
|
) {
|
||||||
|
getSodium().crypto_generichash_update(state.internalState, messagePart.toUInt8Array())
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun genericHashFinal(state: GenericHashState): UByteArray {
|
||||||
|
return getSodium().crypto_generichash_final(state.internalState, state.hashLength).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun genericHashKeygen(): UByteArray {
|
||||||
|
return getSodium().crypto_generichash_keygen().toUByteArray()
|
||||||
|
}
|
||||||
|
// -- Not present in LazySodium nor libsodium.js
|
||||||
|
// actual fun blake2b(message: UByteArray, requestedHashLength: Int, key: UByteArray?) : UByteArray {
|
||||||
|
// return getSodium().crypto_generichash_blake2b(
|
||||||
|
// requestedHashLength,
|
||||||
|
// message.toUInt8Array(),
|
||||||
|
// key?.toUInt8Array() ?: Uint8Array(0)
|
||||||
|
// ).toUByteArray()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// actual fun blake2bInit(
|
||||||
|
// requestedHashLength: Int,
|
||||||
|
// key: UByteArray?
|
||||||
|
// ): Blake2bState {
|
||||||
|
// val state = getSodium().crypto_generichash_blake2b_init(key?.toUInt8Array() ?: Uint8Array(0), requestedHashLength)
|
||||||
|
// return Blake2bState(requestedHashLength, state)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// actual fun blake2bUpdate(
|
||||||
|
// state: GenericHashState,
|
||||||
|
// messagePart: UByteArray
|
||||||
|
// ) {
|
||||||
|
// getSodium().crypto_generichash_blake2b_update(state.internalState, messagePart.toUInt8Array())
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// actual fun blake2bFinal(state: GenericHashState): UByteArray {
|
||||||
|
// return getSodium().crypto_generichash_blake2b_final(state.internalState, state.hashLength).toUByteArray()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// actual fun blake2bKeygen(): UByteArray {
|
||||||
|
// return getSodium().crypto_generichash_blake2b_keygen().toUByteArray()
|
||||||
|
// }
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.hash
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.getSodium
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
|
||||||
|
|
||||||
|
actual typealias Sha256State = Any
|
||||||
|
actual typealias Sha512State = Any
|
||||||
|
|
||||||
|
actual object Hash {
|
||||||
|
|
||||||
|
actual fun sha256(data: UByteArray): UByteArray {
|
||||||
|
return getSodium().crypto_hash_sha256(data.toUInt8Array()).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun sha256Init(): Sha256State {
|
||||||
|
return getSodium().crypto_hash_sha256_init()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun sha256Update(state: Sha256State, data: UByteArray) {
|
||||||
|
getSodium().crypto_hash_sha256_update(state, data.toUInt8Array())
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun sha256Final(state: Sha256State): UByteArray {
|
||||||
|
return getSodium().crypto_hash_sha256_final(state).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun sha512(data: UByteArray): UByteArray {
|
||||||
|
return getSodium().crypto_hash_sha512(data.toUInt8Array()).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun sha512Init(): Sha512State {
|
||||||
|
return getSodium().crypto_hash_sha512_init()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun sha512Update(state: Sha512State, data: UByteArray) {
|
||||||
|
getSodium().crypto_hash_sha512_update(state, data.toUInt8Array())
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun sha512Final(state: Sha512State): UByteArray {
|
||||||
|
return getSodium().crypto_hash_sha512_final(state).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -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 deriveFromKey function derives a subkeyId-th subkey of length subkeyLenght bytes using
|
||||||
|
* the master key key and the context ctx.
|
||||||
|
* subkey_id can be any value up to (2^32) because javascript doesn't support long types.
|
||||||
|
* 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: UInt,
|
||||||
|
subkeyLength: Int,
|
||||||
|
context: String,
|
||||||
|
masterKey: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
return getSodium().crypto_kdf_derive_from_key(
|
||||||
|
subkeyLength.toUInt(),
|
||||||
|
subkeyId,
|
||||||
|
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,57 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.keyexchange
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.getSodium
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
|
||||||
|
import org.khronos.webgl.Uint8Array
|
||||||
|
|
||||||
|
actual object KeyExchange {
|
||||||
|
actual fun clientSessionKeys(clientPublicKey: UByteArray, clientSecretKey: UByteArray, serverPublicKey: UByteArray) : KeyExchangeSessionKeyPair {
|
||||||
|
|
||||||
|
|
||||||
|
val result = getSodium().crypto_kx_client_session_keys(
|
||||||
|
clientPublicKey.toUInt8Array(),
|
||||||
|
clientSecretKey.toUInt8Array(),
|
||||||
|
serverPublicKey.toUInt8Array()
|
||||||
|
)
|
||||||
|
|
||||||
|
val receiveKey = (result.sharedRx as Uint8Array).toUByteArray()
|
||||||
|
val sendKey = (result.sharedTx as Uint8Array).toUByteArray()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return KeyExchangeSessionKeyPair(receiveKey, sendKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun keypair() : KeyExchangeKeyPair {
|
||||||
|
val result = getSodium().crypto_kx_keypair()
|
||||||
|
|
||||||
|
val publicKey = (result.publicKey as Uint8Array).toUByteArray()
|
||||||
|
val secretKey = (result.privateKey as Uint8Array).toUByteArray()
|
||||||
|
|
||||||
|
return KeyExchangeKeyPair(publicKey, secretKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun seedKeypair(seed: UByteArray) : KeyExchangeKeyPair {
|
||||||
|
val result = getSodium().crypto_kx_seed_keypair(seed.toUInt8Array())
|
||||||
|
|
||||||
|
val publicKey = (result.publicKey as Uint8Array).toUByteArray()
|
||||||
|
val secretKey = (result.privateKey as Uint8Array).toUByteArray()
|
||||||
|
|
||||||
|
return KeyExchangeKeyPair(publicKey, secretKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun serverSessionKeys(serverPublicKey: UByteArray, serverSecretKey: UByteArray, clientPublicKey: UByteArray) : KeyExchangeSessionKeyPair {
|
||||||
|
|
||||||
|
val result = getSodium().crypto_kx_server_session_keys(
|
||||||
|
serverPublicKey.toUInt8Array(),
|
||||||
|
serverSecretKey.toUInt8Array(),
|
||||||
|
clientPublicKey.toUInt8Array()
|
||||||
|
)
|
||||||
|
|
||||||
|
val receiveKey = (result.sharedRx as Uint8Array).toUByteArray()
|
||||||
|
val sendKey = (result.sharedTx as Uint8Array).toUByteArray()
|
||||||
|
|
||||||
|
return KeyExchangeSessionKeyPair(receiveKey, sendKey)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.pwhash
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.getSodium
|
||||||
|
import com.ionspin.kotlin.crypto.util.encodeToUByteArray
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
|
||||||
|
|
||||||
|
actual object PasswordHash {
|
||||||
|
/**
|
||||||
|
* The crypto_pwhash() function derives an outlen bytes long key from a password passwd whose length is passwdlen
|
||||||
|
* and a salt whose fixed length is crypto_pwhash_SALTBYTES bytes. passwdlen should be at least crypto_pwhash_
|
||||||
|
* PASSWD_MIN and crypto_pwhash_PASSWD_MAX. outlen should be at least crypto_pwhash_BYTES_MIN = 16 (128 bits) and
|
||||||
|
* at most crypto_pwhash_BYTES_MAX.
|
||||||
|
*
|
||||||
|
* See https://libsodium.gitbook.io/doc/password_hashing/default_phf for more details
|
||||||
|
*/
|
||||||
|
actual fun pwhash(
|
||||||
|
outputLength: Int,
|
||||||
|
password: String,
|
||||||
|
salt: UByteArray,
|
||||||
|
opsLimit: ULong,
|
||||||
|
memLimit: Int,
|
||||||
|
algorithm: Int
|
||||||
|
): UByteArray {
|
||||||
|
if (opsLimit > UInt.MAX_VALUE) {
|
||||||
|
throw RuntimeException("Javascript doesnt support more than ${UInt.MAX_VALUE} for opslimit")
|
||||||
|
}
|
||||||
|
return getSodium().crypto_pwhash(
|
||||||
|
outputLength.toUInt(),
|
||||||
|
password.encodeToUByteArray().toUInt8Array(),
|
||||||
|
salt.toUInt8Array(),
|
||||||
|
opsLimit.toUInt(),
|
||||||
|
memLimit.toUInt(),
|
||||||
|
algorithm.toUInt()
|
||||||
|
).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The crypto_pwhash_str() function puts an ASCII encoded string into out, which includes:
|
||||||
|
* the result of a memory-hard, CPU-intensive hash function applied to the password passwd of length passwdlen
|
||||||
|
* the automatically generated salt used for the previous computation
|
||||||
|
* the other parameters required to verify the password, including the algorithm identifier, its version, opslimit and memlimit.
|
||||||
|
* out must be large enough to hold crypto_pwhash_STRBYTES bytes, but the actual output string may be shorter.
|
||||||
|
* The output string is zero-terminated, includes only ASCII characters and can be safely stored into SQL databases
|
||||||
|
* and other data stores. No extra information has to be stored in order to verify the password.
|
||||||
|
* The function returns 0 on success and -1 if it didn't complete successfully.
|
||||||
|
*/
|
||||||
|
actual fun str(password: String, opslimit: ULong, memlimit: Int): String {
|
||||||
|
if (opslimit > UInt.MAX_VALUE) {
|
||||||
|
throw RuntimeException("Javascript doesnt support more than ${UInt.MAX_VALUE} for opslimit")
|
||||||
|
}
|
||||||
|
return getSodium().crypto_pwhash_str(
|
||||||
|
password.encodeToUByteArray().toUInt8Array(),
|
||||||
|
opslimit.toUInt(),
|
||||||
|
memlimit.toUInt()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a password verification string str matches the parameters opslimit and memlimit, and the current default algorithm.
|
||||||
|
* The function returns 1 if the string appears to be correct, but doesn't match the given parameters. In that situation, applications may want to compute a new hash using the current parameters the next time the user logs in.
|
||||||
|
* The function returns 0 if the parameters already match the given ones.
|
||||||
|
* It returns -1 on error. If it happens, applications may want to compute a correct hash the next time the user logs in.
|
||||||
|
*/
|
||||||
|
actual fun strNeedsRehash(
|
||||||
|
passwordHash: String,
|
||||||
|
opslimit: ULong,
|
||||||
|
memlimit: Int
|
||||||
|
): Int {
|
||||||
|
if (opslimit > UInt.MAX_VALUE) {
|
||||||
|
throw RuntimeException("Javascript doesnt support more than ${UInt.MAX_VALUE} for opslimit")
|
||||||
|
}
|
||||||
|
return if (
|
||||||
|
getSodium().crypto_pwhash_str_needs_rehash(
|
||||||
|
passwordHash,
|
||||||
|
opslimit.toUInt(),
|
||||||
|
memlimit.toUInt()
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* his function verifies that str is a valid password verification string (as generated by crypto_pwhash_str()) for passwd whose length is passwdlen.
|
||||||
|
* str has to be zero-terminated.
|
||||||
|
* It returns 0 if the verification succeeds, and -1 on error.
|
||||||
|
*/
|
||||||
|
actual fun strVerify(passwordHash: String, password: String): Boolean {
|
||||||
|
return getSodium().crypto_pwhash_str_verify(
|
||||||
|
passwordHash,
|
||||||
|
password.encodeToUByteArray().toUInt8Array()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.scalarmult
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.getSodium
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
|
||||||
|
|
||||||
|
actual object ScalarMultiplication {
|
||||||
|
/**
|
||||||
|
* This function can be used to compute a shared secret q given a user's secret key and another user's public key.
|
||||||
|
* n is crypto_scalarmult_SCALARBYTES bytes long, p and the output are crypto_scalarmult_BYTES bytes long.
|
||||||
|
* q represents the X coordinate of a point on the curve. As a result, the number of possible keys is limited to
|
||||||
|
* the group size (≈2^252), which is smaller than the key space.
|
||||||
|
* For this reason, and to mitigate subtle attacks due to the fact many (p, n) pairs produce the same result,
|
||||||
|
* using the output of the multiplication q directly as a shared key is not recommended.
|
||||||
|
* A better way to compute a shared key is h(q ‖ pk1 ‖ pk2), with pk1 and pk2 being the public keys.
|
||||||
|
* By doing so, each party can prove what exact public key they intended to perform a key exchange with
|
||||||
|
* (for a given public key, 11 other public keys producing the same shared secret can be trivially computed).
|
||||||
|
* This can be achieved with the following code snippet:
|
||||||
|
*/
|
||||||
|
actual fun scalarMultiplication(secretKeyN: UByteArray, publicKeyP: UByteArray): UByteArray {
|
||||||
|
val result = getSodium().crypto_scalarmult(secretKeyN.toUInt8Array(), publicKeyP.toUInt8Array())
|
||||||
|
|
||||||
|
return result.toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a user's secret key n (crypto_scalarmult_SCALARBYTES bytes), the crypto_scalarmult_base() function
|
||||||
|
* computes the user's public key and puts it into q (crypto_scalarmult_BYTES bytes).
|
||||||
|
* crypto_scalarmult_BYTES and crypto_scalarmult_SCALARBYTES are provided for consistency,
|
||||||
|
* but it is safe to assume that crypto_scalarmult_BYTES == crypto_scalarmult_SCALARBYTES.
|
||||||
|
*/
|
||||||
|
actual fun scalarMultiplicationBase(
|
||||||
|
secretKeyN: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
val result = getSodium().crypto_scalarmult_base( secretKeyN.toUInt8Array())
|
||||||
|
|
||||||
|
return result.toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.secretbox
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.getSodium
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
|
||||||
|
import org.khronos.webgl.Uint8Array
|
||||||
|
|
||||||
|
actual object SecretBox {
|
||||||
|
actual fun easy(message: UByteArray, nonce: UByteArray, key: UByteArray): UByteArray {
|
||||||
|
return getSodium().crypto_secretbox_easy(
|
||||||
|
message.toUInt8Array(),
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
key.toUInt8Array()
|
||||||
|
).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun openEasy(
|
||||||
|
ciphertext: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
key: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
try {
|
||||||
|
val decryptionResult = getSodium().crypto_secretbox_open_easy(
|
||||||
|
ciphertext.toUInt8Array(),
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
key.toUInt8Array()
|
||||||
|
)
|
||||||
|
return (decryptionResult as Uint8Array).toUByteArray()
|
||||||
|
} catch (error: Throwable) {
|
||||||
|
throw SecretBoxCorruptedOrTamperedDataExceptionOrInvalidKey()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun detached(
|
||||||
|
message: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
key: UByteArray
|
||||||
|
): SecretBoxEncryptedDataAndTag {
|
||||||
|
val result = getSodium().crypto_secretbox_detached(
|
||||||
|
message.toUInt8Array(),
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
key.toUInt8Array()
|
||||||
|
)
|
||||||
|
return SecretBoxEncryptedDataAndTag(
|
||||||
|
(result.cipher as Uint8Array).toUByteArray(),
|
||||||
|
(result.mac as Uint8Array).toUByteArray()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun openDetached(
|
||||||
|
ciphertext: UByteArray,
|
||||||
|
tag: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
key: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
try {
|
||||||
|
val decryptionResult = getSodium().crypto_secretbox_open_detached(
|
||||||
|
ciphertext.toUInt8Array(),
|
||||||
|
tag.toUInt8Array(),
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
key.toUInt8Array()
|
||||||
|
)
|
||||||
|
return (decryptionResult as Uint8Array).toUByteArray()
|
||||||
|
} catch (error: Throwable) {
|
||||||
|
throw SecretBoxCorruptedOrTamperedDataExceptionOrInvalidKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun keygen(): UByteArray {
|
||||||
|
return getSodium().crypto_secretbox_keygen().toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.secretstream
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.getSodium
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
|
||||||
|
import org.khronos.webgl.Uint8Array
|
||||||
|
|
||||||
|
actual typealias SecretStreamState = Any
|
||||||
|
|
||||||
|
actual object SecretStream {
|
||||||
|
actual fun xChaCha20Poly1305InitPush(key: UByteArray): SecretStreamStateAndHeader {
|
||||||
|
val state = getSodium().crypto_secretstream_xchacha20poly1305_init_push(key.toUInt8Array())
|
||||||
|
return SecretStreamStateAndHeader(state.state, (state.header as Uint8Array).toUByteArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun xChaCha20Poly1305Push(
|
||||||
|
state: SecretStreamState,
|
||||||
|
message: UByteArray,
|
||||||
|
associatedData: UByteArray,
|
||||||
|
tag: UByte
|
||||||
|
): UByteArray {
|
||||||
|
return getSodium().crypto_secretstream_xchacha20poly1305_push(
|
||||||
|
state, message.toUInt8Array(), associatedData.toUInt8Array(), tag
|
||||||
|
).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun xChaCha20Poly1305InitPull(
|
||||||
|
key: UByteArray,
|
||||||
|
header: UByteArray
|
||||||
|
): SecretStreamStateAndHeader {
|
||||||
|
val state = getSodium().crypto_secretstream_xchacha20poly1305_init_pull(header.toUInt8Array(), key.toUInt8Array())
|
||||||
|
return SecretStreamStateAndHeader(state, header)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun xChaCha20Poly1305Pull(
|
||||||
|
state: SecretStreamState,
|
||||||
|
ciphertext: UByteArray,
|
||||||
|
associatedData: UByteArray
|
||||||
|
): DecryptedDataAndTag {
|
||||||
|
val dataAndTag = getSodium().crypto_secretstream_xchacha20poly1305_pull(
|
||||||
|
state, ciphertext.toUInt8Array(), associatedData.toUInt8Array()
|
||||||
|
)
|
||||||
|
if (dataAndTag == false) {
|
||||||
|
throw SecretStreamCorruptedOrTamperedDataException()
|
||||||
|
}
|
||||||
|
return DecryptedDataAndTag((dataAndTag.message as Uint8Array).toUByteArray(), dataAndTag.tag)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun xChaCha20Poly1305Keygen(): UByteArray {
|
||||||
|
return getSodium().crypto_shorthash_keygen().toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun xChaCha20Poly1305Rekey(state: SecretStreamState) {
|
||||||
|
getSodium().crypto_secretstream_xchacha20poly1305_rekey(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.shortinputhash
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.getSodium
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Ugljesa Jovanovic
|
||||||
|
* ugljesa.jovanovic@ionspin.com
|
||||||
|
* on 21-Aug-2020
|
||||||
|
*/
|
||||||
|
actual object ShortHash {
|
||||||
|
actual fun shortHash(data: UByteArray, key: UByteArray): UByteArray {
|
||||||
|
return getSodium().crypto_shorthash(data.toUInt8Array(), key.toUInt8Array()).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun shortHashKeygen(): UByteArray {
|
||||||
|
return getSodium().crypto_shorthash_keygen().toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,161 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.signature
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.getSodium
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
|
||||||
|
import org.khronos.webgl.Uint8Array
|
||||||
|
|
||||||
|
actual typealias SignatureState = Any
|
||||||
|
|
||||||
|
actual object Signature {
|
||||||
|
actual fun init(): SignatureState {
|
||||||
|
return getSodium().crypto_sign_init()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun update(state: SignatureState, data: UByteArray) {
|
||||||
|
getSodium().crypto_sign_update(state, data.toUInt8Array())
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun finalCreate(
|
||||||
|
state: SignatureState,
|
||||||
|
secretKey: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
return getSodium().crypto_sign_final_create(
|
||||||
|
state,
|
||||||
|
secretKey.toUInt8Array()
|
||||||
|
).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun finalVerify(
|
||||||
|
state: SignatureState,
|
||||||
|
signature: UByteArray,
|
||||||
|
publicKey: UByteArray
|
||||||
|
) {
|
||||||
|
val verificationResult = getSodium().crypto_sign_final_verify(
|
||||||
|
state,
|
||||||
|
signature.toUInt8Array(),
|
||||||
|
publicKey.toUInt8Array()
|
||||||
|
)
|
||||||
|
if (verificationResult == false) {
|
||||||
|
throw InvalidSignatureException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The crypto_sign_keypair() function randomly generates a secret key and a corresponding public key.
|
||||||
|
* The public key is put into pk (crypto_sign_PUBLICKEYBYTES bytes) and the secret key into sk (crypto_sign_SECRETKEYBYTES bytes).
|
||||||
|
*/
|
||||||
|
actual fun keypair(): SignatureKeyPair {
|
||||||
|
val keypair = getSodium().crypto_sign_keypair()
|
||||||
|
return SignatureKeyPair(
|
||||||
|
(keypair.publicKey as Uint8Array).toUByteArray(),
|
||||||
|
(keypair.privateKey as Uint8Array).toUByteArray()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The crypto_sign_keypair() function randomly generates a secret key and a corresponding public key.
|
||||||
|
* The public key is put into pk (crypto_sign_PUBLICKEYBYTES bytes) and the secret key into sk (crypto_sign_SECRETKEYBYTES bytes).
|
||||||
|
* Using crypto_sign_seed_keypair(), the key pair can also be deterministically derived from a single key seed (crypto_sign_SEEDBYTES bytes).
|
||||||
|
*/
|
||||||
|
actual fun seedKeypair(seed: UByteArray): SignatureKeyPair {
|
||||||
|
val keypair = getSodium().crypto_sign_seed_keypair(seed.toUInt8Array())
|
||||||
|
return SignatureKeyPair(
|
||||||
|
(keypair.publicKey as Uint8Array).toUByteArray(),
|
||||||
|
(keypair.privateKey as Uint8Array).toUByteArray()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The crypto_sign() function prepends a signature to a message m whose length is mlen bytes, using the secret key sk.
|
||||||
|
* The signed message, which includes the signature + a plain copy of the message, is put into sm, and is crypto_sign_BYTES + mlen bytes long.
|
||||||
|
*/
|
||||||
|
actual fun sign(message: UByteArray, secretKey: UByteArray): UByteArray {
|
||||||
|
return getSodium().crypto_sign(
|
||||||
|
message.toUInt8Array(),
|
||||||
|
secretKey.toUInt8Array()
|
||||||
|
).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The crypto_sign_open() function checks that the signed message sm whose length is smlen bytes has a valid signature for the public key pk.
|
||||||
|
* If the signature is doesn't appear to be valid, the function throws an exception
|
||||||
|
*/
|
||||||
|
actual fun open(signedMessage: UByteArray, publicKey: UByteArray): UByteArray {
|
||||||
|
try {
|
||||||
|
return getSodium().crypto_sign_open(
|
||||||
|
signedMessage.toUInt8Array(),
|
||||||
|
publicKey.toUInt8Array()
|
||||||
|
).toUByteArray()
|
||||||
|
} catch (error : Throwable) {
|
||||||
|
throw InvalidSignatureException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In detached mode, the signature is stored without attaching a copy of the original message to it.
|
||||||
|
* The crypto_sign_detached() function signs the message m whose length is mlen bytes, using the secret key sk,
|
||||||
|
* and puts the signature into sig, which can be up to crypto_sign_BYTES bytes long.
|
||||||
|
*/
|
||||||
|
actual fun detached(message: UByteArray, secretKey: UByteArray): UByteArray {
|
||||||
|
return getSodium().crypto_sign_detached(
|
||||||
|
message.toUInt8Array(),
|
||||||
|
secretKey.toUInt8Array()
|
||||||
|
).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The crypto_sign_verify_detached() function verifies that sig is a valid signature for the message m whose length
|
||||||
|
* is mlen bytes, using the signer's public key pk.
|
||||||
|
*/
|
||||||
|
actual fun verifyDetached(signature: UByteArray, message: UByteArray, publicKey: UByteArray) {
|
||||||
|
val verificationResult = getSodium().crypto_sign_verify_detached(
|
||||||
|
signature.toUInt8Array(),
|
||||||
|
message.toUInt8Array(),
|
||||||
|
publicKey.toUInt8Array()
|
||||||
|
)
|
||||||
|
|
||||||
|
if (verificationResult == false) {
|
||||||
|
throw InvalidSignatureException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The crypto_sign_ed25519_pk_to_curve25519() function converts an Ed25519 public key ed25519_pk to an X25519 public key and stores it into x25519_pk.
|
||||||
|
*/
|
||||||
|
actual fun ed25519PkToCurve25519(ed25519PublicKey: UByteArray): UByteArray {
|
||||||
|
return getSodium().crypto_sign_ed25519_pk_to_curve25519(
|
||||||
|
ed25519PublicKey.toUInt8Array()
|
||||||
|
).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The crypto_sign_ed25519_sk_to_curve25519() function converts an Ed25519 secret key ed25519_sk to an X25519 secret key and stores it into x25519_sk.
|
||||||
|
*/
|
||||||
|
actual fun ed25519SkToCurve25519(ed25519SecretKey: UByteArray): UByteArray {
|
||||||
|
return getSodium().crypto_sign_ed25519_sk_to_curve25519(
|
||||||
|
ed25519SecretKey.toUInt8Array()
|
||||||
|
).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The secret key actually includes the seed (either a random seed or the one given to crypto_sign_seed_keypair()) as well as the public key.
|
||||||
|
* While the public key can always be derived from the seed, the precomputation saves a significant amount of CPU cycles when signing.
|
||||||
|
*/
|
||||||
|
actual fun ed25519SkToSeed(secretKey: UByteArray): UByteArray {
|
||||||
|
return getSodium().crypto_sign_ed25519_sk_to_seed(
|
||||||
|
secretKey.toUInt8Array()
|
||||||
|
).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The secret key actually includes the seed (either a random seed or the one given to crypto_sign_seed_keypair()) as well as the public key.
|
||||||
|
* While the public key can always be derived from the seed, the precomputation saves a significant amount of CPU cycles when signing.
|
||||||
|
*/
|
||||||
|
actual fun ed25519SkToPk(secretKey: UByteArray): UByteArray {
|
||||||
|
return getSodium().crypto_sign_ed25519_sk_to_pk(
|
||||||
|
secretKey.toUInt8Array()
|
||||||
|
).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,122 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.stream
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.getSodium
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
|
||||||
|
|
||||||
|
actual object Stream {
|
||||||
|
actual fun chacha20(clen: Int, nonce: UByteArray, key: UByteArray): UByteArray {
|
||||||
|
//Note, unlike the other ones, here the positions of key and nonce are reversed.
|
||||||
|
val result = getSodium().crypto_stream_chacha20(clen.toUInt(), key.toUInt8Array(), nonce.toUInt8Array())
|
||||||
|
|
||||||
|
return result.toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun chacha20IetfXor(
|
||||||
|
message: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
key: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
val result = getSodium().crypto_stream_chacha20_ietf_xor(
|
||||||
|
message.toUInt8Array(),
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
key.toUInt8Array()
|
||||||
|
)
|
||||||
|
|
||||||
|
return result.toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun chacha20IetfXorIc(
|
||||||
|
message: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
initialCounter: UInt,
|
||||||
|
key: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
val result = getSodium().crypto_stream_chacha20_ietf_xor_ic(
|
||||||
|
message.toUInt8Array(),
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
initialCounter,
|
||||||
|
key.toUInt8Array()
|
||||||
|
)
|
||||||
|
|
||||||
|
return result.toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun chacha20Keygen(): UByteArray {
|
||||||
|
val result = getSodium().crypto_stream_chacha20_keygen()
|
||||||
|
|
||||||
|
return result.toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun chacha20Xor(
|
||||||
|
message: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
key: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
val result = getSodium().crypto_stream_chacha20_xor(
|
||||||
|
message.toUInt8Array(),
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
key.toUInt8Array()
|
||||||
|
)
|
||||||
|
|
||||||
|
return result.toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun chacha20XorIc(
|
||||||
|
message: UByteArray,
|
||||||
|
nonce: UByteArray,
|
||||||
|
initialCounter: ULong,
|
||||||
|
key: UByteArray
|
||||||
|
): UByteArray {
|
||||||
|
if (initialCounter > UInt.MAX_VALUE) {
|
||||||
|
throw RuntimeException("Javascript doesnt support more than ${UInt.MAX_VALUE} for initial counter")
|
||||||
|
}
|
||||||
|
val result = getSodium().crypto_stream_chacha20_xor_ic(
|
||||||
|
message.toUInt8Array(),
|
||||||
|
nonce.toUInt8Array(),
|
||||||
|
initialCounter.toUInt(),
|
||||||
|
key.toUInt8Array()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
return result.toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
// actual fun xChacha20Keygen(): UByteArray {
|
||||||
|
// val result = getSodium().crypto_stream_xchacha20_keygen()
|
||||||
|
//
|
||||||
|
// return result.toUByteArray()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// actual fun xChacha20Xor(
|
||||||
|
// message: UByteArray,
|
||||||
|
// nonce: UByteArray,
|
||||||
|
// key: UByteArray
|
||||||
|
// ): UByteArray {
|
||||||
|
// val result = getSodium().crypto_stream_xchacha20_xor(
|
||||||
|
// message.toUInt8Array(),
|
||||||
|
// nonce.toUInt8Array(),
|
||||||
|
// key.toUInt8Array()
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// return result.toUByteArray()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// actual fun xChacha20XorIc(
|
||||||
|
// message: UByteArray,
|
||||||
|
// nonce: UByteArray,
|
||||||
|
// initialCounter: ULong,
|
||||||
|
// key: UByteArray
|
||||||
|
// ): UByteArray {
|
||||||
|
// val result = getSodium().crypto_stream_xchacha20_xor_ic(
|
||||||
|
// message.toUInt8Array(),
|
||||||
|
// nonce.toUInt8Array(),
|
||||||
|
// initialCounter.toUInt(),
|
||||||
|
// key.toUInt8Array()
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// return result.toUByteArray()
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.util
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.getSodium
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Ugljesa Jovanovic
|
||||||
|
* ugljesa.jovanovic@ionspin.com
|
||||||
|
* on 27-Sep-2020
|
||||||
|
*/
|
||||||
|
actual object LibsodiumRandom {
|
||||||
|
/**
|
||||||
|
* The randombytes_buf() function fills size bytes starting at buf with an unpredictable sequence of bytes.
|
||||||
|
*/
|
||||||
|
actual fun buf(size: Int): UByteArray {
|
||||||
|
return getSodium().randombytes_buf(size).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The randombytes_buf_deterministic function stores size bytes into buf indistinguishable from random bytes without knowing seed.
|
||||||
|
* For a given seed, this function will always output the same sequence. size can be up to 2^31 (~8GB) because we use kotlin arrays
|
||||||
|
* and they are limited by Int primitive type
|
||||||
|
* seed is randombytes_SEEDBYTES bytes long.
|
||||||
|
* This function is mainly useful for writing tests, and was introduced in libsodium 1.0.12. Under the hood, it uses the ChaCha20 stream cipher.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
actual fun bufDeterministic(size: Int, seed: UByteArray): UByteArray {
|
||||||
|
return getSodium().randombytes_buf_deterministic(size.toUInt(), seed.toUInt8Array()).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The randombytes_random() function returns an unpredictable value between 0 and 0xffffffff (included).
|
||||||
|
*/
|
||||||
|
actual fun random(): UInt {
|
||||||
|
return getSodium().randombytes_random()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The randombytes_uniform() function returns an unpredictable value between 0 and upper_bound (excluded). Unlike r
|
||||||
|
* andombytes_random() % upper_bound, it guarantees a uniform distribution of the possible output values even when
|
||||||
|
* upper_bound is not a power of 2. Note that an upper_bound < 2 leaves only a single element to be chosen, namely 0
|
||||||
|
*/
|
||||||
|
actual fun uniform(upperBound: UInt): UInt {
|
||||||
|
return getSodium().randombytes_uniform(upperBound)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.util
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.getSodium
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
|
||||||
|
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
|
||||||
|
|
||||||
|
actual object LibsodiumUtil {
|
||||||
|
actual fun memcmp(first: UByteArray, second: UByteArray): Boolean {
|
||||||
|
return getSodium().memcmp(first.toUInt8Array(), second.toUInt8Array())
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun memzero(target: UByteArray) {
|
||||||
|
// libsodium.js does this as well, and theres no clear way at the moment of casting ubytearray to uint8array
|
||||||
|
// although I feel like there should be a way to work around it
|
||||||
|
(target.indices).forEach {
|
||||||
|
index -> target[index] = 0U
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun pad(unpaddedData: UByteArray, blocksize: Int): UByteArray {
|
||||||
|
return getSodium().pad(unpaddedData.toUInt8Array(), blocksize).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun unpad(paddedData: UByteArray, blocksize: Int): UByteArray {
|
||||||
|
return getSodium().unpad(paddedData.toUInt8Array(), blocksize).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun toBase64(
|
||||||
|
data: UByteArray,
|
||||||
|
variant: Base64Variants
|
||||||
|
): String {
|
||||||
|
return getSodium().to_base64(data.toUInt8Array(), variant.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun toHex(data: UByteArray): String {
|
||||||
|
return getSodium().to_hex(data.toUInt8Array())
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun fromBase64(
|
||||||
|
data: String,
|
||||||
|
variant: Base64Variants
|
||||||
|
): UByteArray {
|
||||||
|
return getSodium().from_base64(data, variant.value).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun fromHex(data: String): UByteArray {
|
||||||
|
return getSodium().from_hex(data).toUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,113 @@
|
|||||||
|
//package debug.test
|
||||||
|
//
|
||||||
|
//import com.ionspin.kotlin.crypto.getSodium
|
||||||
|
//import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
|
||||||
|
//import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
|
||||||
|
//import kotlin.Any
|
||||||
|
//import kotlin.Int
|
||||||
|
//import kotlin.UByte
|
||||||
|
//import kotlin.UByteArray
|
||||||
|
//import org.khronos.webgl.Uint8Array
|
||||||
|
//
|
||||||
|
//actual typealias Sha256State = Any
|
||||||
|
//
|
||||||
|
//actual typealias Sha512State = Any
|
||||||
|
//
|
||||||
|
//actual typealias GenericHashState = Any
|
||||||
|
//
|
||||||
|
//actual typealias SecretStreamState = Any
|
||||||
|
//
|
||||||
|
//actual class Crypto internal actual constructor() {
|
||||||
|
// /**
|
||||||
|
// * Initialize the SHA256 hash
|
||||||
|
// * returns sha 256 state
|
||||||
|
// */
|
||||||
|
// actual fun crypto_hash_sha256_init(): dynamic {
|
||||||
|
// println("Debug crypto_hash_sha256_init")
|
||||||
|
// val result = js("getSodium().crypto_hash_sha256_init()")
|
||||||
|
// return result
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// actual fun crypto_hash_sha256_update(state: Sha256State, input: UByteArray) {
|
||||||
|
// println("Debug crypto_hash_sha256_update")
|
||||||
|
// getSodium().crypto_hash_sha256_update(state, input.toUInt8Array())
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// actual fun crypto_hash_sha256_final(state: Sha256State): UByteArray {
|
||||||
|
// println("Debug crypto_hash_sha256_final")
|
||||||
|
// return getSodium().crypto_hash_sha256_final(state).toUByteArray()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// actual fun crypto_hash_sha512_init(): dynamic {
|
||||||
|
// println("Debug crypto_hash_sha512_init")
|
||||||
|
// val result = js("getSodium().crypto_hash_sha512_init()")
|
||||||
|
// return result
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// actual fun crypto_hash_sha512_update(state: Sha512State, input: UByteArray) {
|
||||||
|
// println("Debug crypto_hash_sha512_update")
|
||||||
|
// getSodium().crypto_hash_sha512_update(state, input.toUInt8Array())
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// actual fun crypto_hash_sha512_final(state: Sha512State): UByteArray {
|
||||||
|
// println("Debug crypto_hash_sha512_final")
|
||||||
|
// return getSodium().crypto_hash_sha512_final(state).toUByteArray()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// actual fun crypto_generichash_init(key: UByteArray, outlen: Int): dynamic {
|
||||||
|
// println("Debug crypto_generichash_init")
|
||||||
|
// return getSodium().crypto_generichash_init(key.toUInt8Array(), outlen)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Initialize a state and generate a random header. Both are returned inside
|
||||||
|
// * `SecretStreamStateAndHeader` object.
|
||||||
|
// */
|
||||||
|
// actual fun crypto_secretstream_xchacha20poly1305_init_push(key: UByteArray):
|
||||||
|
// SecretStreamStateAndHeader {
|
||||||
|
// println("Debug crypto_secretstream_xchacha20poly1305_init_push")
|
||||||
|
// val stateAndHeader =
|
||||||
|
// getSodium().crypto_secretstream_xchacha20poly1305_init_push(key.toUInt8Array())
|
||||||
|
// val state = stateAndHeader.state
|
||||||
|
// val header = (stateAndHeader.header as Uint8Array).toUByteArray()
|
||||||
|
// return SecretStreamStateAndHeader(state, header)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Initialize state from header and key. The state can then be used for decryption.
|
||||||
|
// */
|
||||||
|
// actual fun crypto_secretstream_xchacha20poly1305_init_pull(header: UByteArray, key: UByteArray):
|
||||||
|
// dynamic {
|
||||||
|
// println("Debug crypto_secretstream_xchacha20poly1305_init_pull")
|
||||||
|
// return getSodium().crypto_secretstream_xchacha20poly1305_init_pull(header.toUInt8Array(),
|
||||||
|
// key.toUInt8Array())
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Encrypt next block of data using the previously initialized state. Returns encrypted block.
|
||||||
|
// */
|
||||||
|
// actual fun crypto_secretstream_xchacha20poly1305_push(
|
||||||
|
// state: SecretStreamState,
|
||||||
|
// m: UByteArray,
|
||||||
|
// ad: UByteArray,
|
||||||
|
// tag: UByte
|
||||||
|
// ): UByteArray {
|
||||||
|
// println("Debug crypto_secretstream_xchacha20poly1305_push")
|
||||||
|
// return getSodium().crypto_secretstream_xchacha20poly1305_push(state, m.toUInt8Array(),
|
||||||
|
// ad.toUInt8Array(), tag).toUByteArray()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Decrypt next block of data using the previously initialized state. Returns decrypted block.
|
||||||
|
// */
|
||||||
|
// actual fun crypto_secretstream_xchacha20poly1305_pull(
|
||||||
|
// state: SecretStreamState,
|
||||||
|
// c: UByteArray,
|
||||||
|
// ad: UByteArray
|
||||||
|
// ): DecryptedDataAndTag {
|
||||||
|
// println("Debug crypto_secretstream_xchacha20poly1305_pull")
|
||||||
|
//// return getSodium().crypto_secretstream_xchacha20poly1305_pull(state, c.toUInt8Array(),
|
||||||
|
//// ad.toUInt8Array())
|
||||||
|
// return DecryptedDataAndTag(ubyteArrayOf(), 0U)
|
||||||
|
// }
|
||||||
|
//}
|
@ -0,0 +1,31 @@
|
|||||||
|
@file:JsModule("libsodium-sumo")
|
||||||
|
@file:JsNonModule
|
||||||
|
package ext.libsodium
|
||||||
|
|
||||||
|
import org.khronos.webgl.Uint8Array
|
||||||
|
import kotlin.js.Promise
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Ugljesa Jovanovic
|
||||||
|
* ugljesa.jovanovic@ionspin.com
|
||||||
|
* on 25-May-2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
@JsName("ready")
|
||||||
|
external val _libsodiumPromise : Promise<dynamic>
|
||||||
|
|
||||||
|
@JsName("_sodium_init")
|
||||||
|
external fun sodium_init() : Int
|
||||||
|
|
||||||
|
external fun crypto_generichash(hashLength: Int, inputMessage: Uint8Array) : Uint8Array
|
||||||
|
|
||||||
|
external fun crypto_hash_sha256(message: Uint8Array) : Uint8Array
|
||||||
|
external fun crypto_hash_sha512(message: Uint8Array) : Uint8Array
|
||||||
|
|
||||||
|
external fun crypto_hash_sha256_init(): dynamic
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user