Use random bytes provided by libsodium on js, add with callback load for sodium, more progress

This commit is contained in:
Ugljesa Jovanovic 2020-05-28 19:00:33 +02:00 committed by Ugljesa Jovanovic
parent 781c9c1b61
commit f51374ce15
No known key found for this signature in database
GPG Key ID: 178E6DFCECCB0E0F
9 changed files with 75 additions and 38 deletions

View File

@ -74,7 +74,7 @@ kotlin {
js { js {
browser { browser {
testTask { testTask {
enabled = false //Until I sort out testing on travis enabled = true //Until I sort out testing on travis
useKarma { useKarma {
useChrome() useChrome()
} }

View File

@ -23,5 +23,7 @@ object Crypto : CryptoProvider {
expect object Initializer { expect object Initializer {
suspend fun initialize() suspend fun initialize()
fun initializeWithCallback(done : () -> (Unit))
} }

View File

@ -6,7 +6,7 @@ import ext.libsodium.com.ionspin.kotlin.crypto.JsSodiumLoader
lateinit var sodiumPointer : JsSodiumInterface lateinit var sodiumPointer : JsSodiumInterface
var sodiumLoaded: Boolean = false var sodiumLoaded: Boolean = false
fun getSodiumPointer() : JsSodiumInterface = sodiumPointer fun getSodium() : JsSodiumInterface = sodiumPointer
fun setSodiumPointer(jsSodiumInterface: JsSodiumInterface) { fun setSodiumPointer(jsSodiumInterface: JsSodiumInterface) {
js("sodiumPointer = jsSodiumInterface") js("sodiumPointer = jsSodiumInterface")
@ -22,4 +22,10 @@ actual object Initializer {
actual suspend fun initialize() { actual suspend fun initialize() {
JsSodiumLoader.load() JsSodiumLoader.load()
} }
actual fun initializeWithCallback(done: () -> Unit) {
}
} }

View File

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

View File

@ -1,7 +1,6 @@
package ext.libsodium.com.ionspin.kotlin.crypto package ext.libsodium.com.ionspin.kotlin.crypto
import com.ionspin.kotlin.crypto.getSodiumLoaded import com.ionspin.kotlin.crypto.getSodiumLoaded
import com.ionspin.kotlin.crypto.getSodiumPointer
import com.ionspin.kotlin.crypto.setSodiumPointer import com.ionspin.kotlin.crypto.setSodiumPointer
import com.ionspin.kotlin.crypto.sodiumLoaded import com.ionspin.kotlin.crypto.sodiumLoaded
import ext.libsodium._libsodiumPromise import ext.libsodium._libsodiumPromise
@ -15,19 +14,33 @@ import kotlin.coroutines.suspendCoroutine
*/ */
object JsSodiumLoader { object JsSodiumLoader {
fun storeSodium(promisedSodium: dynamic, continuation: Continuation<JsSodiumInterface>) { fun storeSodium(promisedSodium: dynamic, continuation: Continuation<Unit>) {
setSodiumPointer(promisedSodium) setSodiumPointer(promisedSodium)
sodiumLoaded = true sodiumLoaded = true
continuation.resumeWith(Result.success(getSodiumPointer())) continuation.resumeWith(Result.success(Unit))
} }
suspend fun load(): JsSodiumInterface = suspendCoroutine { continuation -> suspend fun load() = suspendCoroutine<Unit> { continuation ->
console.log(getSodiumLoaded()) console.log(getSodiumLoaded())
if (!getSodiumLoaded()) { if (!getSodiumLoaded()) {
val libsodiumModule = js("\$module\$libsodium_wrappers_sumo") val libsodiumModule = js("\$module\$libsodium_wrappers_sumo")
_libsodiumPromise.then<dynamic> { storeSodium(libsodiumModule, continuation) } _libsodiumPromise.then<dynamic> { storeSodium(libsodiumModule, continuation) }
} else { } else {
continuation.resumeWith(Result.success(getSodiumPointer())) continuation.resumeWith(Result.success(Unit))
}
}
fun loadWithCallback(doneCallback: () -> (Unit)) {
console.log(getSodiumLoaded())
if (!getSodiumLoaded()) {
val libsodiumModule = js("\$module\$libsodium_wrappers_sumo")
_libsodiumPromise.then<dynamic> {
setSodiumPointer(libsodiumModule)
sodiumLoaded = true
doneCallback.invoke()
}
} else {
doneCallback.invoke()
} }
} }
} }

View File

@ -16,7 +16,7 @@
package com.ionspin.kotlin.crypto package com.ionspin.kotlin.crypto
import kotlin.browser.window import org.khronos.webgl.get
/** /**
* Created by Ugljesa Jovanovic * Created by Ugljesa Jovanovic
@ -27,22 +27,7 @@ actual object SRNG {
var counter = 0 var counter = 0
@ExperimentalUnsignedTypes @ExperimentalUnsignedTypes
actual fun getRandomBytes(amount: Int): UByteArray { actual fun getRandomBytes(amount: Int): UByteArray {
val runningOnNode = jsTypeOf(window) == "undefined" val randomBytes = getSodium().randombytes_buf(amount)
val randomBytes = if (runningOnNode) {
println("Running on node")
js("require('crypto')").randomBytes(amount).toJSON().data
} else {
println("Running in browser")
js(
"""
var randomArray = new Uint8Array(amount);
var crypto = (self.crypto || self.msCrypto);
crypto.getRandomValues(randomArray);
"""
)
var randomArrayResult = js("Array.prototype.slice.call(randomArray);")
randomArrayResult
}
println("Random bytes: $randomBytes") println("Random bytes: $randomBytes")
print("Byte at ${randomBytes[0]}") print("Byte at ${randomBytes[0]}")
val randomBytesUByteArray = UByteArray(amount) { val randomBytesUByteArray = UByteArray(amount) {

View File

@ -1,9 +1,7 @@
package com.ionspin.kotlin.crypto.hash.blake2b package com.ionspin.kotlin.crypto.hash.blake2b
import com.ionspin.kotlin.crypto.getSodium
import com.ionspin.kotlin.crypto.util.toHexString 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 * Created by Ugljesa Jovanovic
@ -39,8 +37,7 @@ actual object Blake2bStateless : Blake2bStatelessInterface {
override val MAX_HASH_BYTES: Int = 64 override val MAX_HASH_BYTES: Int = 64
override suspend fun digest(inputString: String, key: String?, hashLength: Int): UByteArray { override suspend fun digest(inputString: String, key: String?, hashLength: Int): UByteArray {
val sodium = JsSodiumLoader.load() val hashed = getSodium().crypto_generichash(64, inputString)
val hashed = sodium.crypto_generichash(64, inputString)
val hash = UByteArray(MAX_HASH_BYTES) val hash = UByteArray(MAX_HASH_BYTES)
for (i in 0 until MAX_HASH_BYTES) { for (i in 0 until MAX_HASH_BYTES) {
js( js(
@ -50,7 +47,21 @@ actual object Blake2bStateless : Blake2bStatelessInterface {
) )
} }
println("Hash ${hash.toHexString()}") println("Hash ${hash.toHexString()}")
return ubyteArrayOf(0U) return hash
}
fun digestBlocking(inputString: String, key: String?, hashLength: Int): UByteArray {
val hashed = getSodium().crypto_generichash(hashLength, 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 hash
} }
override fun digest(inputMessage: UByteArray, key: UByteArray, hashLength: Int): UByteArray { override fun digest(inputMessage: UByteArray, key: UByteArray, hashLength: Int): UByteArray {

View File

@ -16,6 +16,8 @@
package com.ionspin.kotlin.crypto package com.ionspin.kotlin.crypto
import com.ionspin.kotlin.crypto.util.testBlocking
import ext.libsodium.com.ionspin.kotlin.crypto.JsSodiumLoader
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertTrue import kotlin.test.assertTrue
@ -28,14 +30,15 @@ import kotlin.test.assertTrue
class SRNGJsTest { class SRNGJsTest {
@Test @Test
fun testJsSrng() { fun testJsSrng() = testBlocking {
JsSodiumLoader.load()
val bytes1 = SRNG.getRandomBytes(10) val bytes1 = SRNG.getRandomBytes(10)
val bytes2 = SRNG.getRandomBytes(10) val bytes2 = SRNG.getRandomBytes(10)
println("BYTES1") println("BYTES1\n")
bytes1.forEach { bytes1.forEach {
print(it.toString(16).padStart(2, '0')) print(it.toString(16).padStart(2, '0'))
} }
println("BYTES2") println("BYTES2\n")
bytes2.forEach { bytes2.forEach {
print(it.toString(16).padStart(2, '0')) print(it.toString(16).padStart(2, '0'))
} }

View File

@ -2,8 +2,10 @@ package com.ionspin.kotlin.crypto.hash.blake2b
import com.ionspin.kotlin.crypto.Crypto import com.ionspin.kotlin.crypto.Crypto
import com.ionspin.kotlin.crypto.util.testBlocking import com.ionspin.kotlin.crypto.util.testBlocking
import com.ionspin.kotlin.crypto.util.toHexString
import kotlin.test.BeforeTest import kotlin.test.BeforeTest
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals
/** /**
* Created by Ugljesa Jovanovic * Created by Ugljesa Jovanovic
@ -14,13 +16,21 @@ import kotlin.test.Test
@ExperimentalStdlibApi @ExperimentalStdlibApi
class Blake2bJsTest { class Blake2bJsTest {
@BeforeTest @Test
fun setup() = testBlocking { fun testBlake2BSodiumInterop() = testBlocking {
Crypto.initialize() Crypto.initialize()
val hash = Blake2bStateless.digest("test")
assertEquals(hash.toHexString(), "a71079d42853dea26e453004338670a53814b78137ffbed07603a41d76a4" +
"83aa9bc33b582f77d30a65e6f29a896c0411f38312e1d66e0bf16386c86a89bea572")
} }
@Test @Test
fun testBlake2BSodiumInterop() = testBlocking { fun testBlake2BSodiumBlockingInterop() = testBlocking {
Blake2bStateless.digest("test") Crypto.initialize()
val hash = Blake2bStateless.digestBlocking("test", null, 64)
assertEquals(hash.toHexString(), "a71079d42853dea26e453004338670a53814b78137ffbed07603a41d76a4" +
"83aa9bc33b582f77d30a65e6f29a896c0411f38312e1d66e0bf16386c86a89bea572")
} }
} }