Working js libsodium, need to change apis to suspend

This commit is contained in:
Ugljesa Jovanovic 2020-05-27 23:49:08 +02:00 committed by Ugljesa Jovanovic
parent 1009b92d33
commit 781c9c1b61
No known key found for this signature in database
GPG Key ID: 178E6DFCECCB0E0F
20 changed files with 153 additions and 26 deletions

View File

@ -50,8 +50,8 @@ object Deps {
val serialization = "org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:${Versions.kotlinSerialization}"
object Npm {
val libsodium = Pair("libsodium", "0.7.6")
val libsodiumWrappers = Pair("libsodium-wrappers", "0.7.6")
val libsodium = Pair("libsodium-sumo", "0.7.6")
val libsodiumWrappers = Pair("libsodium-wrappers-sumo", "0.7.6")
}
}

View File

@ -18,6 +18,7 @@ org.gradle.parallel=true
kotlin.code.style=official
kotlin.js.compiler=ir
#kotlin.js.experimental.generateKotlinExternals=true
kotlin.mpp.enableGranularSourceSetsMetadata=true
org.gradle.jvmargs=-Xmx4g -XX:MaxPermSize=4096m

View File

@ -0,0 +1,12 @@
package com.ionspin.kotlin.crypto
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 27-May-2020
*/
interface CryptoProvider {
suspend fun initialize()
}

View File

@ -39,7 +39,7 @@ interface UpdatableHash : Hash {
@ExperimentalUnsignedTypes
interface StatelessHash : Hash {
fun digest(inputString: String, key: String? = null, hashLength: Int = MAX_HASH_BYTES): UByteArray
suspend fun digest(inputString: String, key: String? = null, hashLength: Int = MAX_HASH_BYTES): UByteArray
fun digest(
inputMessage: UByteArray = ubyteArrayOf(),

View File

@ -12,4 +12,16 @@ import com.ionspin.kotlin.crypto.hash.sha.Sha512Pure
typealias Sha256Stateless = Sha256Pure.Companion
typealias Sha512Stateless = Sha512Pure.Companion
typealias Sha512Stateless = Sha512Pure.Companion
object Crypto : CryptoProvider {
override suspend fun initialize() {
Initializer.initialize()
}
}
expect object Initializer {
suspend fun initialize()
}

View File

@ -66,7 +66,7 @@ class Sha256Pure : Sha256 {
)
@ExperimentalStdlibApi
override fun digest(inputString: String, key: String?, hashLength: Int): UByteArray {
override suspend fun digest(inputString: String, key: String?, hashLength: Int): UByteArray {
return digest(
inputString.encodeToByteArray().toUByteArray(),
key?.run { encodeToByteArray().toUByteArray()} ?: ubyteArrayOf(),

View File

@ -134,7 +134,7 @@ class Sha512Pure : Sha512 {
)
@ExperimentalStdlibApi
override fun digest(inputString: String, key: String?, hashLength: Int): UByteArray {
override suspend fun digest(inputString: String, key: String?, hashLength: Int): UByteArray {
return digest(
inputString.encodeToByteArray().toUByteArray(),
key?.run { encodeToByteArray().toUByteArray() } ?: ubyteArrayOf(),

View File

@ -0,0 +1,25 @@
package com.ionspin.kotlin.crypto
import ext.libsodium.com.ionspin.kotlin.crypto.JsSodiumInterface
import ext.libsodium.com.ionspin.kotlin.crypto.JsSodiumLoader
/* 1.4-M1 has some weirdness with static/objects, or I'm misusing something, not sure */
lateinit var sodiumPointer : JsSodiumInterface
var sodiumLoaded: Boolean = false
fun getSodiumPointer() : JsSodiumInterface = sodiumPointer
fun setSodiumPointer(jsSodiumInterface: JsSodiumInterface) {
js("sodiumPointer = jsSodiumInterface")
}
fun getSodiumLoaded() : Boolean = sodiumLoaded
fun setSodiumLoaded(loaded: Boolean) {
js("sodiumLoaded = loaded")
}
actual object Initializer {
actual suspend fun initialize() {
JsSodiumLoader.load()
}
}

View File

@ -0,0 +1,10 @@
package ext.libsodium.com.ionspin.kotlin.crypto
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 27-May-2020
*/
interface JsSodiumInterface {
fun crypto_generichash(hashLength: Int, inputMessage: String) : String
}

View File

@ -0,0 +1,33 @@
package ext.libsodium.com.ionspin.kotlin.crypto
import com.ionspin.kotlin.crypto.getSodiumLoaded
import com.ionspin.kotlin.crypto.getSodiumPointer
import com.ionspin.kotlin.crypto.setSodiumPointer
import com.ionspin.kotlin.crypto.sodiumLoaded
import ext.libsodium._libsodiumPromise
import kotlin.coroutines.Continuation
import kotlin.coroutines.suspendCoroutine
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 27-May-2020
*/
object JsSodiumLoader {
fun storeSodium(promisedSodium: dynamic, continuation: Continuation<JsSodiumInterface>) {
setSodiumPointer(promisedSodium)
sodiumLoaded = true
continuation.resumeWith(Result.success(getSodiumPointer()))
}
suspend fun load(): JsSodiumInterface = suspendCoroutine { continuation ->
console.log(getSodiumLoaded())
if (!getSodiumLoaded()) {
val libsodiumModule = js("\$module\$libsodium_wrappers_sumo")
_libsodiumPromise.then<dynamic> { storeSodium(libsodiumModule, continuation) }
} else {
continuation.resumeWith(Result.success(getSodiumPointer()))
}
}
}

View File

@ -1,9 +1,9 @@
package com.ionspin.kotlin.crypto.hash.blake2b
import crypto_generichash
import org.khronos.webgl.Uint8Array
import org.khronos.webgl.get
import kotlin.js.Promise
import com.ionspin.kotlin.crypto.util.toHexString
import ext.libsodium.com.ionspin.kotlin.crypto.JsSodiumInterface
import ext.libsodium.com.ionspin.kotlin.crypto.JsSodiumLoader
import ext.libsodium.crypto_generichash
/**
* Created by Ugljesa Jovanovic
@ -38,12 +38,18 @@ actual class Blake2bDelegated actual constructor(key: UByteArray?, hashLength: I
actual object Blake2bStateless : Blake2bStatelessInterface {
override val MAX_HASH_BYTES: Int = 64
override fun digest(inputString: String, key: String?, hashLength: Int): UByteArray {
// val hashed = crypto_generichash(64, Uint8Array(inputString.encodeToByteArray().toTypedArray()), null)
// return UByteArray(MAX_HASH_BYTES) { hashed[it].toUByte() }
val hash = crypto_generichash(64, Uint8Array(arrayOf(0U.toByte())));
println("Hash $hash")
override suspend fun digest(inputString: String, key: String?, hashLength: Int): UByteArray {
val sodium = JsSodiumLoader.load()
val hashed = sodium.crypto_generichash(64, inputString)
val hash = UByteArray(MAX_HASH_BYTES)
for (i in 0 until MAX_HASH_BYTES) {
js(
"""
hash[i] = hashed[i]
"""
)
}
println("Hash ${hash.toHexString()}")
return ubyteArrayOf(0U)
}
@ -52,5 +58,4 @@ actual object Blake2bStateless : Blake2bStatelessInterface {
}
}

View File

@ -1,10 +1,19 @@
@file:JsModule("libsodium-wrappers-sumo")
@file:JsNonModule
package ext.libsodium
import org.khronos.webgl.Uint8Array
import kotlin.js.Promise
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 25-May-2020
*/
@JsModule("libsodium")
@JsNonModule
external fun crypto_generichash(hashLength: Int, inputMessage: Uint8Array) : Uint8Array
@JsName("ready")
external val _libsodiumPromise : Promise<dynamic>
external fun crypto_generichash(hashLength: Int, inputMessage: String) : String

View File

@ -1,5 +1,8 @@
package com.ionspin.kotlin.crypto.hash.blake2b
import com.ionspin.kotlin.crypto.Crypto
import com.ionspin.kotlin.crypto.util.testBlocking
import kotlin.test.BeforeTest
import kotlin.test.Test
/**
@ -11,8 +14,13 @@ import kotlin.test.Test
@ExperimentalStdlibApi
class Blake2bJsTest {
@BeforeTest
fun setup() = testBlocking {
Crypto.initialize()
}
@Test
fun testBlake2BSodiumInterop() {
fun testBlake2BSodiumInterop() = testBlocking {
Blake2bStateless.digest("test")
}
}

View File

@ -0,0 +1,6 @@
package com.ionspin.kotlin.crypto
actual object Initializer {
actual suspend fun initialize() {
}
}

View File

@ -29,7 +29,7 @@ actual class Blake2bDelegated actual constructor(key: UByteArray?, hashLength: I
}
@ExperimentalUnsignedTypes
actual object Blake2bStateless : Blake2bStatelessInterface {
override fun digest(inputString: String, key: String?, hashLength: Int): UByteArray {
suspend override fun digest(inputString: String, key: String?, hashLength: Int): UByteArray {
TODO("not implemented yet")
}

View File

@ -0,0 +1,6 @@
package com.ionspin.kotlin.crypto
actual object Initializer {
actual suspend fun initialize() {
}
}

View File

@ -34,7 +34,7 @@ actual class Blake2bDelegated actual constructor(key: UByteArray?, hashLength: I
@Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
actual object Blake2bStateless : Blake2bStatelessInterface {
override fun digest(inputString: String, key: String?, hashLength: Int): UByteArray {
suspend override fun digest(inputString: String, key: String?, hashLength: Int): UByteArray {
val hashResult = UByteArray(MAX_HASH_BYTES)
val hashResultPinned = hashResult.pin()
crypto_generichash(

View File

@ -145,7 +145,7 @@ class Blake2bPure(val key: UByteArray? = null, val hashLength: Int = 64) : Blake
}
@ExperimentalStdlibApi
override fun digest(inputString: String, key: String?, hashLength: Int): UByteArray {
override suspend fun digest(inputString: String, key: String?, hashLength: Int): UByteArray {
val array = inputString.encodeToByteArray().toUByteArray()
val keyBytes = key?.run {
encodeToByteArray().toUByteArray()

View File

@ -66,7 +66,7 @@ class Sha256Pure : Sha256 {
)
@ExperimentalStdlibApi
override fun digest(inputString: String, key: String?, hashLength: Int): UByteArray {
suspend override fun digest(inputString: String, key: String?, hashLength: Int): UByteArray {
return digest(
inputString.encodeToByteArray().toUByteArray(),
key?.run { encodeToByteArray().toUByteArray()} ?: ubyteArrayOf(),

View File

@ -134,7 +134,7 @@ class Sha512Pure : Sha512 {
)
@ExperimentalStdlibApi
override fun digest(inputString: String, key: String?, hashLength: Int): UByteArray {
override suspend fun digest(inputString: String, key: String?, hashLength: Int): UByteArray {
return digest(
inputString.encodeToByteArray().toUByteArray(),
key?.run { encodeToByteArray().toUByteArray() } ?: ubyteArrayOf(),