Merge pull request #1 from sergeych/develop2
Some checks failed
Build project and push to maven snapshot / Build-And-Push-Linux (push) Has been cancelled
Build project and push to maven snapshot / Build-And-Push-Mac (push) Has been cancelled
Build project and push to maven snapshot / Build-And-Push-Windows (push) Has been cancelled

Develop changes
This commit is contained in:
Kildishev Petr 2025-01-23 00:59:17 +03:00 committed by GitHub
commit 186db7478a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
51 changed files with 3070 additions and 434 deletions

View File

@ -18,9 +18,9 @@
buildscript {
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.23")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.21")
classpath("com.android.tools.build:gradle:7.2.2")
classpath ("org.jetbrains.dokka:dokka-gradle-plugin:1.9.20")
classpath("org.jetbrains.dokka:dokka-gradle-plugin:1.9.20")
}
repositories {

View File

@ -28,7 +28,7 @@ repositories {
}
dependencies {
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.23")
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.21")
implementation("com.android.tools.build:gradle:7.2.2")
implementation ("org.jetbrains.dokka:dokka-gradle-plugin:1.9.20")
}

View File

@ -16,7 +16,8 @@
object Versions {
val kotlinCoroutines = "1.8.0"
val kotlin = "1.9.23"
val kotlinCoroutinesTest = "1.9.0"
val kotlin = "2.0.21"
val kotlinSerialization = "1.6.3"
val kotlinSerializationPlugin = kotlin
val taskTreePlugin = "1.5"
@ -36,7 +37,7 @@ object Versions {
object ReleaseInfo {
val group = "com.ionspin.kotlin"
val bindingsVersion = "0.9.3-SNAPSHOT"
val bindingsVersion = "0.9.4-SNAPSHOT"
}
object Deps {
@ -46,6 +47,7 @@ object Deps {
val test = "test-common"
val testAnnotation = "test-annotations-common"
val coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.kotlinCoroutines}"
val coroutinesTest = "org.jetbrains.kotlinx:kotlinx-coroutines-test:${Versions.kotlinCoroutinesTest}"
val serialization = "org.jetbrains.kotlinx:kotlinx-serialization-json:${Versions.kotlinSerialization}"
val kotlinBigNum = "com.ionspin.kotlin:bignum:${Versions.kotlinBigNumVersion}"
@ -72,6 +74,13 @@ object Deps {
}
object wasmJs {
object Npm {
val libsodiumWrappers = Pair("libsodium-wrappers-sumo", "0.7.13")
}
}
object Jvm {
val stdLib = "stdlib-jdk8"
val test = "test"

View File

@ -26,3 +26,5 @@ org.gradle.jvmargs=-Xmx4g
android.useAndroidX=true
kotlin.js.webpack.major.version=4
kotlin.mpp.applyDefaultHierarchyTemplate=false

View File

@ -1,21 +1,6 @@
#
# Copyright 2019 Ugljesa Jovanovic
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#Mon Nov 11 15:13:29 MSK 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

File diff suppressed because it is too large Load Diff

View File

@ -17,6 +17,7 @@
@file:Suppress("UnstableApiUsage")
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeTest
plugins {
@ -39,6 +40,7 @@ kotlin {
val hostOsName = getHostOsName()
runningOnLinuxx86_64 {
jvm()
js(IR) {
browser {
testTask {
@ -57,6 +59,16 @@ kotlin {
}
}
@OptIn(ExperimentalWasmDsl::class)
wasmJs {
browser {
testTask {
useKarma {
useChrome()
}
}
}
}
linuxX64("linux") {
binaries {
staticLib {
@ -112,6 +124,8 @@ kotlin {
dependencies {
implementation(kotlin(Deps.Common.test))
implementation(kotlin(Deps.Common.testAnnotation))
implementation(Deps.Common.coroutinesTest)
implementation(kotlin("test"))
}
}
@ -140,8 +154,17 @@ kotlin {
implementation(kotlin(Deps.Js.test))
}
}
val wasmJsMain by getting {
dependencies {
implementation(npm(Deps.wasmJs.Npm.libsodiumWrappers.first, Deps.wasmJs.Npm.libsodiumWrappers.second))
}
}
val wasmJsTest by getting {
dependencies {
implementation(npm(Deps.wasmJs.Npm.libsodiumWrappers.first, Deps.wasmJs.Npm.libsodiumWrappers.second))
}
}
}
runningOnMacos {
val tvosX64Main by getting {
dependsOn(commonMain)

View File

@ -17,10 +17,11 @@
@file:Suppress("UnstableApiUsage")
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeTest
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
plugins {
kotlin(PluginsDeps.multiplatform)
@ -88,11 +89,11 @@ kotlin {
}
jvm()
val projectRef = project
runningOnLinuxx86_64 {
println("Configuring Linux X86-64 targets")
js {
browser {
testTask {
@ -110,6 +111,18 @@ kotlin {
}
}
@OptIn(ExperimentalWasmDsl::class)
wasmJs {
browser {
testTask {
useKarma {
useChrome()
}
}
}
}
linuxX64() {
compilations.getByName("main") {
val libsodiumCinterop by cinterops.creating {
@ -293,6 +306,8 @@ kotlin {
implementation(kotlin(Deps.Common.test))
implementation(kotlin(Deps.Common.testAnnotation))
implementation(Deps.Common.coroutines)
implementation(Deps.Common.coroutinesTest)
implementation(kotlin("test"))
}
}
@ -374,7 +389,7 @@ kotlin {
)
)
compilations.getByName("main") {
this@withType.compilations.getByName("main") {
val libsodiumCinterop by cinterops.creating {
defFile(projectRef.file("src/nativeInterop/cinterop/libsodium.def"))
compilerOpts.add("-I${projectRef.rootDir}/sodiumWrapper/static-arm64/include/")
@ -557,7 +572,6 @@ kotlin {
runningOnLinuxx86_64 {
println("Configuring Linux 64 Bit source sets")
val jsMain by getting {
dependencies {
implementation(kotlin(Deps.Js.stdLib))
@ -570,6 +584,17 @@ kotlin {
implementation(npm(Deps.Js.Npm.libsodiumWrappers.first, Deps.Js.Npm.libsodiumWrappers.second))
}
}
val wasmJsMain by getting {
dependencies {
implementation(npm(Deps.wasmJs.Npm.libsodiumWrappers.first, Deps.wasmJs.Npm.libsodiumWrappers.second))
}
}
val wasmJsTest by getting {
dependencies {
implementation(npm(Deps.wasmJs.Npm.libsodiumWrappers.first, Deps.wasmJs.Npm.libsodiumWrappers.second))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0")
}
}
val linuxX64Main by getting {
isRunningInIdea {
kotlin.srcDir("src/nativeMain/kotlin")
@ -671,16 +696,15 @@ tasks {
}
val jvmTest by getting(Test::class) {
testLogging {
events("PASSED", "FAILED", "SKIPPED")
exceptionFormat = TestExceptionFormat.FULL
showStandardStreams = true
showStackTraces = true
}
}
if (getHostOsName() == "linux" && getHostArchitecture() == "x86-64") {
val jvmTest by getting(Test::class) {
testLogging {
events("PASSED", "FAILED", "SKIPPED")
exceptionFormat = TestExceptionFormat.FULL
showStandardStreams = true
showStackTraces = true
}
}
val linuxX64Test by getting(KotlinNativeTest::class) {
@ -707,6 +731,13 @@ tasks {
// events("PASSED", "FAILED", "SKIPPED")
// showStandardStreams = true
// }
// }
// val wasmJsBrowserTest by getting(KotlinJsTest::class) {
// testLogging {
// events("PASSED", "FAILED", "SKIPPED")
// showStandardStreams = true
// }
// }
val jsBrowserTest by getting(KotlinJsTest::class) {

View File

@ -4,7 +4,6 @@ import com.ionspin.kotlin.crypto.generichash.GenericHash
import com.ionspin.kotlin.crypto.util.encodeToUByteArray
import com.ionspin.kotlin.crypto.util.testBlocking
import com.ionspin.kotlin.crypto.util.toHexString
import com.ionspin.kotlin.crypto.util.runTest
import kotlin.test.Test
import kotlin.test.assertTrue

View File

@ -36,6 +36,6 @@ fun testBlocking(block : suspend () -> Unit) {
block.startCoroutine(continuation)
}
expect fun runTest(block: suspend (scope : CoroutineScope) -> Unit)
fun runTest(block: suspend (scope : CoroutineScope) -> Unit) = kotlinx.coroutines.test.runTest { block(this) }

View File

@ -1,7 +1,7 @@
package com.ionspin.kotlin.crypto.util
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.promise
actual fun runTest(block: suspend (scope : CoroutineScope) -> Unit): dynamic = GlobalScope.promise { block(this) }
//import kotlinx.coroutines.CoroutineScope
//import kotlinx.coroutines.GlobalScope
//import kotlinx.coroutines.promise
//
//actual fun runTest(block: suspend (scope : CoroutineScope) -> Unit): dynamic = GlobalScope.promise { block(this) }

View File

@ -1,7 +1,7 @@
package com.ionspin.kotlin.crypto.util
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.runBlocking
actual fun runTest(block: suspend (scope : CoroutineScope) -> Unit) = runBlocking { block(this) }
//import kotlinx.coroutines.CoroutineScope
//import kotlinx.coroutines.runBlocking
//
//actual fun runTest(block: suspend (scope : CoroutineScope) -> Unit) = runBlocking { block(this) }

View File

@ -1,7 +1,7 @@
package com.ionspin.kotlin.crypto.util
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.runBlocking
actual fun runTest(block: suspend (scope : CoroutineScope) -> Unit) = runBlocking { block(this) }
//import kotlinx.coroutines.CoroutineScope
//import kotlinx.coroutines.runBlocking
//
//actual fun runTest(block: suspend (scope : CoroutineScope) -> Unit) = runBlocking { block(this) }

View File

@ -0,0 +1,477 @@
package ext.libsodium.com.ionspin.kotlin.crypto
import org.khronos.webgl.Uint8Array
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 27-May-2020
*/
@JsModule("libsodium-wrappers-sumo")
external object JsSodium: JsAny {
@JsName("default")
val default : JsSodiumInterface
}
@JsModule("libsodium-wrappers-sumo")
external object JsSodiumInterface: JsAny {
@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) : GenericHashStateInternalType
@JsName("crypto_generichash_update")
fun crypto_generichash_update(state: GenericHashStateInternalType, inputMessage: Uint8Array)
@JsName("crypto_generichash_final")
fun crypto_generichash_final(state: GenericHashStateInternalType, hashLength: Int) : Uint8Array
@JsName("crypto_generichash_keygen")
fun crypto_generichash_keygen() : Uint8Array
// ---- Generic hash end ---- // Updateable
// ---- Blake2b ----
// I
@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) : Blake2bInternalStateType
@JsName("crypto_generichash_blake2b_update")
fun crypto_generichash_blake2b_update(state: Blake2bInternalStateType, inputMessage: Uint8Array)
@JsName("crypto_generichash_blake2b_final")
fun crypto_generichash_blake2b_final(state: Blake2bInternalStateType, 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() : Sha256StateType
@JsName("crypto_hash_sha256_update")
fun crypto_hash_sha256_update(state: Sha256StateType, message: Uint8Array)
@JsName("crypto_hash_sha256_final")
fun crypto_hash_sha256_final(state: Sha256StateType): Uint8Array
@JsName("crypto_hash_sha512_init")
fun crypto_hash_sha512_init() : Sha512StateType
@JsName("crypto_hash_sha512_update")
fun crypto_hash_sha512_update(state: Sha512StateType, message: Uint8Array)
@JsName("crypto_hash_sha512_final")
fun crypto_hash_sha512_final(state: Sha512StateType): 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) : SecretStreamStateAndHeaderType
@JsName("crypto_secretstream_xchacha20poly1305_push")
fun crypto_secretstream_xchacha20poly1305_push(state: SecretStreamStateType, message: Uint8Array, associatedData: Uint8Array, tag: Byte) : Uint8Array
//decrypt
@JsName("crypto_secretstream_xchacha20poly1305_init_pull")
fun crypto_secretstream_xchacha20poly1305_init_pull(header: Uint8Array, key: Uint8Array) : SecretStreamStateType
@JsName("crypto_secretstream_xchacha20poly1305_pull")
fun crypto_secretstream_xchacha20poly1305_pull(state: SecretStreamStateType, ciphertext: Uint8Array, associatedData: Uint8Array) : DecryptedDataAndTagType
//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: SecretStreamStateType)
// ---- SecretBox ----
@JsName("crypto_secretbox_detached")
fun crypto_secretbox_detached(message: Uint8Array, nonce: Uint8Array, key: Uint8Array) : SecretBoxEncryptedType
@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) : Uint8Array
@JsName("crypto_secretbox_open_easy")
fun crypto_secretbox_open_easy(ciphertext : Uint8Array, nonce: Uint8Array, key: Uint8Array) : Uint8Array
// ---- 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) : AeadEncryptedType
@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) : AeadEncryptedType
@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) : AeadEncryptedType
@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() : KeyExchangeKeyPairType
@JsName("crypto_box_seed_keypair")
fun crypto_box_seed_keypair(seed : Uint8Array) : KeyExchangeKeyPairType
@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) : BoxEncryptedType
@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: SignatureStateType, secretKey: Uint8Array) : Uint8Array
@JsName("crypto_sign_final_verify")
fun crypto_sign_final_verify(state: SignatureStateType, signature: Uint8Array, publicKey: Uint8Array) : Boolean
@JsName("crypto_sign_init")
fun crypto_sign_init() : SignatureStateType
@JsName("crypto_sign_keypair")
fun crypto_sign_keypair() : KeyExchangeKeyPairType
@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) : KeyExchangeKeyPairType
@JsName("crypto_sign_update")
fun crypto_sign_update(state: SignatureStateType, 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: Int, subkeyId : Int, 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 : Int, password : Uint8Array, salt: Uint8Array, opsLimit: Int, memLimit: Int, algorithm: Int) : Uint8Array
@JsName("crypto_pwhash_str")
fun crypto_pwhash_str(password: Uint8Array, opsLimit: Int, memLimit: Int) : String
@JsName("crypto_pwhash_str_needs_rehash")
fun crypto_pwhash_str_needs_rehash(hashedPassword: String, opsLimit: Int, memLimit: Int) : 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: Int, seed : Uint8Array) : Uint8Array
@JsName("randombytes_random")
fun randombytes_random() : Int
@JsName("randombytes_uniform")
fun randombytes_uniform(upper_bound: Int) : Int
// ---- Utils end ----
// ---- Key exchange ----
@JsName("crypto_kx_client_session_keys")
fun crypto_kx_client_session_keys(clientPublicKey: Uint8Array, clientSecretKey: Uint8Array, serverPublicKey: Uint8Array) : KeyExchangeSessionKeyPairType
@JsName("crypto_kx_keypair")
fun crypto_kx_keypair() : KeyExchangeKeyPairType
@JsName("crypto_kx_seed_keypair")
fun crypto_kx_seed_keypair(seed: Uint8Array) : KeyExchangeKeyPairType
@JsName("crypto_kx_server_session_keys")
fun crypto_kx_server_session_keys(serverPublicKey: Uint8Array, serverSecretKey: Uint8Array, clientPublicKey: Uint8Array) : KeyExchangeSessionKeyPairType
// ---- Key exchange end ----
// -- Stream ----
@JsName("crypto_stream_chacha20")
fun crypto_stream_chacha20(outLength: Int, 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: Int, 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: Int, 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: Int, 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 ----
//
// ---- Ristretto255 ----
@JsName("crypto_core_ristretto255_is_valid_point")
fun crypto_core_ristretto255_is_valid_point(p: Uint8Array): Boolean
@JsName("crypto_core_ristretto255_random")
fun crypto_core_ristretto255_random(): Uint8Array
@JsName("crypto_core_ristretto255_from_hash")
fun crypto_core_ristretto255_from_hash(r: Uint8Array): Uint8Array
@JsName("crypto_core_ristretto255_add")
fun crypto_core_ristretto255_add(p: Uint8Array, q: Uint8Array): Uint8Array
@JsName("crypto_core_ristretto255_sub")
fun crypto_core_ristretto255_sub(p: Uint8Array, q: Uint8Array): Uint8Array
@JsName("crypto_core_ristretto255_scalar_random")
fun crypto_core_ristretto255_scalar_random(): Uint8Array
@JsName("crypto_core_ristretto255_scalar_reduce")
fun crypto_core_ristretto255_scalar_reduce(s: Uint8Array): Uint8Array
@JsName("crypto_core_ristretto255_scalar_invert")
fun crypto_core_ristretto255_scalar_invert(s: Uint8Array): Uint8Array
@JsName("crypto_core_ristretto255_scalar_negate")
fun crypto_core_ristretto255_scalar_negate(s: Uint8Array): Uint8Array
@JsName("crypto_core_ristretto255_scalar_complement")
fun crypto_core_ristretto255_scalar_complement(s: Uint8Array): Uint8Array
@JsName("crypto_core_ristretto255_scalar_add")
fun crypto_core_ristretto255_scalar_add(x: Uint8Array, y: Uint8Array): Uint8Array
@JsName("crypto_core_ristretto255_scalar_sub")
fun crypto_core_ristretto255_scalar_sub(x: Uint8Array, y: Uint8Array): Uint8Array
@JsName("crypto_core_ristretto255_scalar_mul")
fun crypto_core_ristretto255_scalar_mul(x: Uint8Array, y: Uint8Array): Uint8Array
@JsName("crypto_scalarmult_ristretto255")
fun crypto_scalarmult_ristretto255(n: Uint8Array, p: Uint8Array): Uint8Array
@JsName("crypto_scalarmult_ristretto255_base")
fun crypto_scalarmult_ristretto255_base(n: Uint8Array): Uint8Array
//
// ---- Ristretto255 end ----
//
// ---- Ed25519 ----
@JsName("crypto_core_ed25519_is_valid_point")
fun crypto_core_ed25519_is_valid_point(p: Uint8Array): Boolean
@JsName("crypto_core_ed25519_random")
fun crypto_core_ed25519_random(): Uint8Array
@JsName("crypto_core_ed25519_from_uniform")
fun crypto_core_ed25519_from_uniform(r: Uint8Array): Uint8Array
@JsName("crypto_core_ed25519_add")
fun crypto_core_ed25519_add(p: Uint8Array, q: Uint8Array): Uint8Array
@JsName("crypto_core_ed25519_sub")
fun crypto_core_ed25519_sub(p: Uint8Array, q: Uint8Array): Uint8Array
@JsName("crypto_core_ed25519_scalar_random")
fun crypto_core_ed25519_scalar_random(): Uint8Array
@JsName("crypto_core_ed25519_scalar_reduce")
fun crypto_core_ed25519_scalar_reduce(s: Uint8Array): Uint8Array
@JsName("crypto_core_ed25519_scalar_invert")
fun crypto_core_ed25519_scalar_invert(s: Uint8Array): Uint8Array
@JsName("crypto_core_ed25519_scalar_negate")
fun crypto_core_ed25519_scalar_negate(s: Uint8Array): Uint8Array
@JsName("crypto_core_ed25519_scalar_complement")
fun crypto_core_ed25519_scalar_complement(s: Uint8Array): Uint8Array
@JsName("crypto_core_ed25519_scalar_add")
fun crypto_core_ed25519_scalar_add(x: Uint8Array, y: Uint8Array): Uint8Array
@JsName("crypto_core_ed25519_scalar_sub")
fun crypto_core_ed25519_scalar_sub(x: Uint8Array, y: Uint8Array): Uint8Array
@JsName("crypto_core_ed25519_scalar_mul")
fun crypto_core_ed25519_scalar_mul(x: Uint8Array, y: Uint8Array): Uint8Array
@JsName("crypto_scalarmult_ed25519")
fun crypto_scalarmult_ed25519(n: Uint8Array, p: Uint8Array): Uint8Array
@JsName("crypto_scalarmult_ed25519_noclamp")
fun crypto_scalarmult_ed25519_noclamp(n: Uint8Array, p: Uint8Array): Uint8Array
@JsName("crypto_scalarmult_ed25519_base")
fun crypto_scalarmult_ed25519_base(n: Uint8Array): Uint8Array
@JsName("crypto_scalarmult_ed25519_base_noclamp")
fun crypto_scalarmult_ed25519_base_noclamp(n: Uint8Array): Uint8Array
//
// ---- Ed25519 end ----
}

View File

@ -0,0 +1,58 @@
package ext.libsodium.com.ionspin.kotlin.crypto
import com.ionspin.kotlin.crypto.getSodiumLoaded
import com.ionspin.kotlin.crypto.sodiumLoaded
import ext.libsodium.*
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(): Unit = suspendCoroutine { continuation ->
if (!getSodiumLoaded()) {
_libsodiumPromise.then<JsAny?> {
sodium_init()
sodiumLoaded = true
continuation.resumeWith(Result.success(Unit))
null
}.catch { e ->
val throwable = e.toThrowableOrNull()
if (throwable != null) {
continuation.resumeWith(Result.failure(throwable))
} else {
continuation.resumeWith(Result.failure(Throwable("Unknown error", throwable)))
}
null
}
} else {
continuation.resumeWith(Result.success(Unit))
}
}
fun loadWithCallback(doneCallback: () -> (Unit)) {
if (!getSodiumLoaded()) {
_libsodiumPromise.then<JsAny?> {
sodium_init()
sodiumLoaded = true
doneCallback.invoke()
null
}
} else {
doneCallback.invoke()
}
}
}

View File

@ -0,0 +1,35 @@
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.toByteArray() : ByteArray {
return toByteArray()
}
fun UByteArray.toUInt8Array() : Uint8Array {
var jsArray = JsArray<JsNumber>()
for (i in this.indices) {
jsArray[i] = this[i].toInt().toJsNumber()
}
var uint8Result = Uint8Array(jsArray)
return uint8Result
}
fun Uint8Array.toUByteArray() : UByteArray {
if (length == null) {
println("Error")
}
val result = UByteArray(length)
for (i in 0 until length) {
result[i] = get(i).toUByte()
}
return result
}

View File

@ -0,0 +1,38 @@
package com.ionspin.kotlin.crypto
import ext.libsodium.com.ionspin.kotlin.crypto.JsSodium
import ext.libsodium.com.ionspin.kotlin.crypto.JsSodiumInterface
import ext.libsodium.com.ionspin.kotlin.crypto.JsSodiumLoader
var sodiumLoaded: Boolean = false
fun getSodium() : JsSodiumInterface = JsSodium.default
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
}
}

View File

@ -0,0 +1,50 @@
package ext.libsodium.com.ionspin.kotlin.crypto
import org.khronos.webgl.Uint8Array
external object Sha256StateType: JsAny
external object Sha512StateType: JsAny
external object SignatureStateType: JsAny
external object AeadEncryptedType : JsAny {
val ciphertext: Uint8Array
var mac: Uint8Array
}
external object BoxEncryptedType : JsAny {
val ciphertext: Uint8Array
var mac: Uint8Array
}
external object KeyExchangeSessionKeyPairType: JsAny {
val sharedRx: Uint8Array
val sharedTx: Uint8Array
}
external object KeyExchangeKeyPairType: JsAny {
val publicKey: Uint8Array
val privateKey: Uint8Array
}
external object SecretBoxEncryptedType: JsAny {
val cipher: Uint8Array
val mac: Uint8Array
}
external object SecretStreamStateType: JsAny
external object SecretStreamStateAndHeaderType: JsAny {
val state: SecretStreamStateType
val header: Uint8Array
}
external object DecryptedDataAndTagType: JsAny {
val message: Uint8Array
val tag: Byte
}
external object GenericHashStateInternalType: JsAny
external object Blake2bInternalStateType: JsAny

View File

@ -0,0 +1,245 @@
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
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).toUByteArray(),
(result.mac).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.toUByteArray(),
result.mac.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.toUByteArray(),
result.mac.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()
}
}

View File

@ -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()
)
}
}

View File

@ -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).toUByteArray(),
(keypair.privateKey).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).toUByteArray(),
(keypair.privateKey).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).toUByteArray(),
(detached.mac).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()
}
}
}

View File

@ -0,0 +1,106 @@
package com.ionspin.kotlin.crypto.ed25519
import com.ionspin.kotlin.crypto.getSodium
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
actual object Ed25519LowLevel {
actual fun isValidPoint(encoded: UByteArray): Boolean =
getSodium().crypto_core_ed25519_is_valid_point(encoded.toUInt8Array())
actual fun addPoints(p: UByteArray, q: UByteArray): UByteArray {
val result = getSodium().crypto_core_ed25519_add(p.toUInt8Array(), q.toUInt8Array())
return result.toUByteArray()
}
actual fun subtractPoints(p: UByteArray, q: UByteArray): UByteArray {
val result = getSodium().crypto_core_ed25519_sub(p.toUInt8Array(), q.toUInt8Array())
return result.toUByteArray()
}
actual fun pointFromUniform(uniform: UByteArray): UByteArray {
val result = getSodium().crypto_core_ed25519_from_uniform(uniform.toUInt8Array())
return result.toUByteArray()
}
actual fun randomPoint(): UByteArray {
val result = getSodium().crypto_core_ed25519_random()
return result.toUByteArray()
}
actual fun randomScalar(): UByteArray {
val result = getSodium().crypto_core_ed25519_scalar_random()
return result.toUByteArray()
}
actual fun invertScalar(scalar: UByteArray): UByteArray {
val result = getSodium().crypto_core_ed25519_scalar_invert(scalar.toUInt8Array())
return result.toUByteArray()
}
actual fun negateScalar(scalar: UByteArray): UByteArray {
val result = getSodium().crypto_core_ed25519_scalar_negate(scalar.toUInt8Array())
return result.toUByteArray()
}
actual fun complementScalar(scalar: UByteArray): UByteArray {
val result = getSodium().crypto_core_ed25519_scalar_complement(scalar.toUInt8Array())
return result.toUByteArray()
}
actual fun addScalars(x: UByteArray, y: UByteArray): UByteArray {
val result = getSodium().crypto_core_ed25519_scalar_add(x.toUInt8Array(), y.toUInt8Array())
return result.toUByteArray()
}
actual fun subtractScalars(x: UByteArray, y: UByteArray): UByteArray {
val result = getSodium().crypto_core_ed25519_scalar_sub(x.toUInt8Array(), y.toUInt8Array())
return result.toUByteArray()
}
actual fun multiplyScalars(x: UByteArray, y: UByteArray): UByteArray {
val result = getSodium().crypto_core_ed25519_scalar_mul(x.toUInt8Array(), y.toUInt8Array())
return result.toUByteArray()
}
actual fun reduceScalar(scalar: UByteArray): UByteArray {
val result = getSodium().crypto_core_ed25519_scalar_reduce(scalar.toUInt8Array())
return result.toUByteArray()
}
actual fun scalarMultiplication(n: UByteArray, p: UByteArray): UByteArray {
val result = getSodium().crypto_scalarmult_ed25519(n.toUInt8Array(), p.toUInt8Array())
return result.toUByteArray()
}
actual fun scalarMultiplicationNoClamp(n: UByteArray, p: UByteArray): UByteArray {
val result = getSodium().crypto_scalarmult_ed25519_noclamp(n.toUInt8Array(), p.toUInt8Array())
return result.toUByteArray()
}
actual fun scalarMultiplicationBase(n: UByteArray): UByteArray {
val result = getSodium().crypto_scalarmult_ed25519_base(n.toUInt8Array())
return result.toUByteArray()
}
actual fun scalarMultiplicationBaseNoClamp(n: UByteArray): UByteArray {
val result = getSodium().crypto_scalarmult_ed25519_base_noclamp(n.toUInt8Array())
return result.toUByteArray()
}
}

View File

@ -0,0 +1,83 @@
package com.ionspin.kotlin.crypto.generichash
import com.ionspin.kotlin.crypto.getSodium
import ext.libsodium.com.ionspin.kotlin.crypto.GenericHashStateInternalType
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 = GenericHashStateInternalType
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()
// }
}

View File

@ -0,0 +1,48 @@
package com.ionspin.kotlin.crypto.hash
import com.ionspin.kotlin.crypto.getSodium
import ext.libsodium.com.ionspin.kotlin.crypto.Sha256StateType
import ext.libsodium.com.ionspin.kotlin.crypto.Sha512StateType
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
actual typealias Sha256State = Sha256StateType
actual typealias Sha512State = Sha512StateType
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()
}
}

View File

@ -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,
subkeyId.toInt(),
context,
masterKey.toUInt8Array()
).toUByteArray()
}
/**
* The crypto_kdf_keygen() function creates a master key.
*/
actual fun keygen(): UByteArray {
return getSodium().crypto_kdf_keygen().toUByteArray()
}
}

View File

@ -0,0 +1,59 @@
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()
)
// Он был в dynamic, но его нет в JsAny
val receiveKey = result.sharedRx.toUByteArray()
val sendKey = result.sharedTx.toUByteArray()
return KeyExchangeSessionKeyPair(receiveKey, sendKey)
}
actual fun keypair() : KeyExchangeKeyPair {
val result = getSodium().crypto_kx_keypair()
val publicKey = result.publicKey.toUByteArray()
val secretKey = result.privateKey.toUByteArray()
return KeyExchangeKeyPair(publicKey, secretKey)
}
actual fun seedKeypair(seed: UByteArray) : KeyExchangeKeyPair {
val result = getSodium().crypto_kx_seed_keypair(seed.toUInt8Array())
val publicKey = result.publicKey.toUByteArray()
val secretKey = result.privateKey.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.toUByteArray()
val sendKey = result.sharedTx.toUByteArray()
return KeyExchangeSessionKeyPair(receiveKey, sendKey)
}
}

View File

@ -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,
password.encodeToUByteArray().toUInt8Array(),
salt.toUInt8Array(),
opsLimit.toInt(),
memLimit,
algorithm
).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.toInt(),
memlimit
)
}
/**
* 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.toInt(),
memlimit
)
) {
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()
)
}
}

View File

@ -0,0 +1,94 @@
package com.ionspin.kotlin.crypto.ristretto255
import com.ionspin.kotlin.crypto.getSodium
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
actual object Ristretto255LowLevel {
actual fun isValidPoint(encoded: UByteArray): Boolean =
getSodium().crypto_core_ristretto255_is_valid_point(encoded.toUInt8Array())
actual fun addPoints(p: UByteArray, q: UByteArray): UByteArray {
val result = getSodium().crypto_core_ristretto255_add(p.toUInt8Array(), q.toUInt8Array())
return result.toUByteArray()
}
actual fun subtractPoints(p: UByteArray, q: UByteArray): UByteArray {
val result = getSodium().crypto_core_ristretto255_sub(p.toUInt8Array(), q.toUInt8Array())
return result.toUByteArray()
}
actual fun pointFromHash(hash: UByteArray): UByteArray {
val result = getSodium().crypto_core_ristretto255_from_hash(hash.toUInt8Array())
return result.toUByteArray()
}
actual fun randomPoint(): UByteArray {
val result = getSodium().crypto_core_ristretto255_random()
return result.toUByteArray()
}
actual fun randomScalar(): UByteArray {
val result = getSodium().crypto_core_ristretto255_scalar_random()
return result.toUByteArray()
}
actual fun invertScalar(scalar: UByteArray): UByteArray {
val result = getSodium().crypto_core_ristretto255_scalar_invert(scalar.toUInt8Array())
return result.toUByteArray()
}
actual fun negateScalar(scalar: UByteArray): UByteArray {
val result = getSodium().crypto_core_ristretto255_scalar_negate(scalar.toUInt8Array())
return result.toUByteArray()
}
actual fun complementScalar(scalar: UByteArray): UByteArray {
val result = getSodium().crypto_core_ristretto255_scalar_complement(scalar.toUInt8Array())
return result.toUByteArray()
}
actual fun addScalars(x: UByteArray, y: UByteArray): UByteArray {
val result = getSodium().crypto_core_ristretto255_scalar_add(x.toUInt8Array(), y.toUInt8Array())
return result.toUByteArray()
}
actual fun subtractScalars(x: UByteArray, y: UByteArray): UByteArray {
val result = getSodium().crypto_core_ristretto255_scalar_sub(x.toUInt8Array(), y.toUInt8Array())
return result.toUByteArray()
}
actual fun multiplyScalars(x: UByteArray, y: UByteArray): UByteArray {
val result = getSodium().crypto_core_ristretto255_scalar_mul(x.toUInt8Array(), y.toUInt8Array())
return result.toUByteArray()
}
actual fun reduceScalar(scalar: UByteArray): UByteArray {
val result = getSodium().crypto_core_ristretto255_scalar_reduce(scalar.toUInt8Array())
return result.toUByteArray()
}
actual fun scalarMultiplication(n: UByteArray, p: UByteArray): UByteArray {
val result = getSodium().crypto_scalarmult_ristretto255(n.toUInt8Array(), p.toUInt8Array())
return result.toUByteArray()
}
actual fun scalarMultiplicationBase(n: UByteArray): UByteArray {
val result = getSodium().crypto_scalarmult_ristretto255_base(n.toUInt8Array())
return result.toUByteArray()
}
}

View File

@ -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()
}
}

View File

@ -0,0 +1,73 @@
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
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.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.toUByteArray(),
result.mac.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.toUByteArray()
} catch (error: Throwable) {
throw SecretBoxCorruptedOrTamperedDataExceptionOrInvalidKey()
}
}
actual fun keygen(): UByteArray {
return getSodium().crypto_secretbox_keygen().toUByteArray()
}
}

View File

@ -0,0 +1,59 @@
package com.ionspin.kotlin.crypto.secretstream
import com.ionspin.kotlin.crypto.getSodium
import ext.libsodium.com.ionspin.kotlin.crypto.SecretStreamStateType
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
actual typealias SecretStreamState = SecretStreamStateType
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.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.toByte()
).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 {
try {
val dataAndTag = getSodium().crypto_secretstream_xchacha20poly1305_pull(
state, ciphertext.toUInt8Array(), associatedData.toUInt8Array()
)
return DecryptedDataAndTag(dataAndTag.message.toUByteArray(), dataAndTag.tag.toUByte())
} catch (error: Throwable) {
throw SecretStreamCorruptedOrTamperedDataException()
}
}
actual fun xChaCha20Poly1305Keygen(): UByteArray {
return getSodium().crypto_shorthash_keygen().toUByteArray()
}
actual fun xChaCha20Poly1305Rekey(state: SecretStreamState) {
getSodium().crypto_secretstream_xchacha20poly1305_rekey(state)
}
}

View File

@ -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()
}
}

View File

@ -0,0 +1,164 @@
package com.ionspin.kotlin.crypto.signature
import com.ionspin.kotlin.crypto.getSodium
import ext.libsodium.com.ionspin.kotlin.crypto.SignatureStateType
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
import org.khronos.webgl.Uint8Array
actual typealias SignatureState = SignatureStateType
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.toUByteArray(),
keypair.privateKey.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.toUByteArray(),
keypair.privateKey.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()
}
}

View File

@ -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, 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.toInt(),
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.toInt(),
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()
// }
}

View File

@ -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, seed.toUInt8Array()).toUByteArray()
}
/**
* The randombytes_random() function returns an unpredictable value between 0 and 0xffffffff (included).
*/
actual fun random(): UInt {
return getSodium().randombytes_random().toUInt()
}
/**
* 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.toInt()).toUInt()
}
}

View File

@ -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()
}
}

View File

@ -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)
// }
//}

View File

@ -0,0 +1,30 @@
@file:JsModule("libsodium-sumo")
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<JsAny?>
@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(): JsAny

View File

@ -0,0 +1,11 @@
//package com.ionspin.kotlin.crypto.debug
import kotlin.test.Test
import kotlin.test.assertEquals
class TestTest {
@Test
fun wasmSymbolsTest() {
assertEquals(42, 42)
}
}

View File

@ -0,0 +1,9 @@
package com.ionspin.kotlin.crypto.debug
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 08-Feb-2021
*/
class DebugTest {
}

View File

@ -0,0 +1,11 @@
package com.ionspin.kotlin.crypto.debug
import kotlin.test.Test
import kotlin.test.assertEquals
class WasmSymbolsTest {
@Test
fun wasmSymbolsTest() {
assertEquals(42, 42)
}
}

View File

@ -0,0 +1,4 @@
package com.ionspin.kotlin.crypto.secretstream
actual fun modifyState(state: SecretStreamState, forceNonce: UByteArray) {
}

View File

@ -0,0 +1,10 @@
package com.ionspin.kotlin.crypto.util
//import kotlinx.coroutines.CoroutineScope
//actual fun runTest(block: suspend (scope : CoroutineScope) -> Unit) {
// kotlinx.coroutines.test.runTest {
// block(this)
// }
//}

View File

@ -0,0 +1,4 @@
config.resolve.alias = {
"crypto": false,
// "path": false,
}

17
package-lock.json generated Normal file
View File

@ -0,0 +1,17 @@
{
"name": "kotlin-multiplatform-libsodium",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"libsodium-sumo": "^0.7.15"
}
},
"node_modules/libsodium-sumo": {
"version": "0.7.15",
"resolved": "https://registry.npmjs.org/libsodium-sumo/-/libsodium-sumo-0.7.15.tgz",
"integrity": "sha512-5tPmqPmq8T8Nikpm1Nqj0hBHvsLFCXvdhBFV7SGOitQPZAA6jso8XoL0r4L7vmfKXr486fiQInvErHtEvizFMw=="
}
}
}

View File

@ -17,9 +17,9 @@
@file:Suppress("UnstableApiUsage")
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeTest
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeTest
import org.jetbrains.kotlin.gradle.tasks.FatFrameworkTask
plugins {
@ -81,8 +81,20 @@ kotlin {
binaries.executable()
}
@OptIn(ExperimentalWasmDsl::class)
wasmJs {
browser {
webpackTask {
}
testTask {
useKarma {
useChrome()
}
}
}
binaries.executable()
}
linuxX64("linux") {
binaries {
executable {
@ -183,6 +195,8 @@ kotlin {
dependencies {
implementation(kotlin(Deps.Common.test))
implementation(kotlin(Deps.Common.testAnnotation))
implementation(Deps.Common.coroutinesTest)
implementation(kotlin("test"))
}
}
@ -207,8 +221,6 @@ kotlin {
}
}
// val nativeMain by creating {
// dependsOn(commonMain)
// dependencies {
@ -282,7 +294,16 @@ kotlin {
implementation(kotlin(Deps.Js.test))
}
}
val wasmJsMain by getting {
dependencies {
implementation(npm(Deps.wasmJs.Npm.libsodiumWrappers.first, Deps.wasmJs.Npm.libsodiumWrappers.second))
}
}
val wasmJsTest by getting {
dependencies {
implementation(npm(Deps.wasmJs.Npm.libsodiumWrappers.first, Deps.wasmJs.Npm.libsodiumWrappers.second))
}
}
val linuxMain by getting {
dependsOn(nativeMain)
}

View File

@ -0,0 +1,15 @@
import com.ionspin.kotlin.crypto.LibsodiumInitializer
import com.ionspin.kotlin.crypto.getSodium
import com.ionspin.kotlin.crypto.hash.Hash
import com.ionspin.kotlin.crypto.util.encodeToUByteArray
import ext.libsodium.com.ionspin.kotlin.crypto.JsSodiumInterface
fun main() {
LibsodiumInitializer.initializeWithCallback {
val hash = Hash.sha512("123".encodeToUByteArray())
println("Hash (SHA512) of 123: ${hash.toHexString()}")
}
}

View File

@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Libsodium bindings sample app!</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
</head>
<body>
<div id="root"></div>
<script src="sample.js"></script>
</body>
</html>

View File

@ -1,7 +1,7 @@
config.devServer = config.devServer || {}
config.devServer.port = 8081
config.devServer.open = false
config.devServer.watchOptions = {
"aggregateTimeout": 1000,
"poll": 1000
}
//config.devServer.watchOptions = {
// "aggregateTimeout": 1000,
// "poll": 1000
//}

View File

@ -19,6 +19,7 @@ pluginManagement {
repositories {
mavenCentral()
maven("https://plugins.gradle.org/m2/")
gradlePluginPortal()
}
resolutionStrategy {
@ -28,6 +29,11 @@ pluginManagement {
}
}
}
plugins {
kotlin("multiplatform") version "2.0.21"
kotlin("plugin.serialization") version "2.0.0"
}
}
rootProject.name = "KotlinMultiplatformLibsodium"
include("multiplatform-crypto-api")