Merge pull request #1 from sergeych/develop2
Some checks failed
Some checks failed
Develop changes
This commit is contained in:
commit
186db7478a
@ -18,7 +18,7 @@
|
||||
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")
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -26,3 +26,5 @@ org.gradle.jvmargs=-Xmx4g
|
||||
android.useAndroidX=true
|
||||
|
||||
kotlin.js.webpack.major.version=4
|
||||
|
||||
kotlin.mpp.applyDefaultHierarchyTemplate=false
|
||||
|
19
gradle/wrapper/gradle-wrapper.properties
vendored
19
gradle/wrapper/gradle-wrapper.properties
vendored
@ -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
@ -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)
|
||||
|
@ -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,6 +696,7 @@ tasks {
|
||||
|
||||
}
|
||||
|
||||
if (getHostOsName() == "linux" && getHostArchitecture() == "x86-64") {
|
||||
val jvmTest by getting(Test::class) {
|
||||
testLogging {
|
||||
events("PASSED", "FAILED", "SKIPPED")
|
||||
@ -680,8 +706,6 @@ tasks {
|
||||
}
|
||||
}
|
||||
|
||||
if (getHostOsName() == "linux" && getHostArchitecture() == "x86-64") {
|
||||
|
||||
val linuxX64Test by getting(KotlinNativeTest::class) {
|
||||
|
||||
testLogging {
|
||||
@ -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) {
|
||||
|
@ -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
|
||||
|
||||
|
@ -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) }
|
||||
|
||||
|
||||
|
@ -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) }
|
||||
|
@ -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) }
|
||||
|
||||
|
@ -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) }
|
||||
|
||||
|
@ -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 ----
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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
|
@ -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()
|
||||
}
|
||||
|
||||
}
|
@ -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).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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
@ -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()
|
||||
// }
|
||||
}
|
@ -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()
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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()
|
||||
}
|
||||
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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()
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
@ -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,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()
|
||||
}
|
||||
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
@ -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,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()
|
||||
}
|
||||
|
||||
}
|
@ -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()
|
||||
// }
|
||||
|
||||
|
||||
}
|
@ -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()
|
||||
}
|
||||
|
||||
}
|
@ -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,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
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.ionspin.kotlin.crypto.debug
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
* ugljesa.jovanovic@ionspin.com
|
||||
* on 08-Feb-2021
|
||||
*/
|
||||
class DebugTest {
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package com.ionspin.kotlin.crypto.secretstream
|
||||
|
||||
actual fun modifyState(state: SecretStreamState, forceNonce: UByteArray) {
|
||||
}
|
@ -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)
|
||||
// }
|
||||
//}
|
@ -0,0 +1,4 @@
|
||||
config.resolve.alias = {
|
||||
"crypto": false,
|
||||
// "path": false,
|
||||
}
|
17
package-lock.json
generated
Normal file
17
package-lock.json
generated
Normal 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=="
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
@ -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()}")
|
||||
}
|
||||
}
|
12
sample/src/wasmJsMain/resources/index.html
Normal file
12
sample/src/wasmJsMain/resources/index.html
Normal 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>
|
@ -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
|
||||
//}
|
@ -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")
|
||||
|
Loading…
x
Reference in New Issue
Block a user