From 67d80beb3443949a063b870a2dfc7d81166321b3 Mon Sep 17 00:00:00 2001 From: Ugljesa Jovanovic Date: Mon, 12 Oct 2020 20:00:17 +0200 Subject: [PATCH] Added _steam_ jvm and js implementations --- .../kotlin/crypto/stream/StreamTest.kt | 72 ++++++++------ .../kotlin/crypto/JsSodiumInterface.kt | 10 ++ .../ionspin/kotlin/crypto/stream/Stream.kt | 82 ++++++++++++++++ .../ionspin/kotlin/crypto/stream/Stream.kt | 98 +++++++++++++++++++ 4 files changed, 230 insertions(+), 32 deletions(-) create mode 100644 multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/stream/Stream.kt create mode 100644 multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/stream/Stream.kt diff --git a/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/stream/StreamTest.kt b/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/stream/StreamTest.kt index 9afe16c..f86bfeb 100644 --- a/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/stream/StreamTest.kt +++ b/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/stream/StreamTest.kt @@ -1,5 +1,6 @@ package com.ionspin.kotlin.crypto.stream +import com.ionspin.kotlin.crypto.LibsodiumInitializer import com.ionspin.kotlin.crypto.util.LibsodiumRandom import com.ionspin.kotlin.crypto.util.encodeToUByteArray import com.ionspin.kotlin.crypto.util.randombytes_SEEDBYTES @@ -20,43 +21,50 @@ class StreamTest { @Test fun testChaCha20Stream() { - val message = "This is a cha cha message".encodeToUByteArray() - val nonce = LibsodiumRandom.bufDeterministic(crypto_stream_chacha20_NONCEBYTES, seed) - val key = Stream.chacha20Keygen() - val stream = Stream.chacha20(message.size, nonce, key) - val encryptedManually = message.mapIndexed { index, it -> it xor stream[index] }.toUByteArray() - val encryptedUsingLibsodium = Stream.chacha20Xor(message, nonce, key) - val encryptedUsingLibsodiumWithInitialCounter = Stream.chacha20XorIc(message, nonce, 0U, key) - println(encryptedManually.toHexString()) - println(encryptedUsingLibsodium.toHexString()) - println(encryptedUsingLibsodiumWithInitialCounter.toHexString()) - assertTrue { - encryptedManually.contentEquals(encryptedUsingLibsodium) - } - assertTrue { - encryptedManually.contentEquals(encryptedUsingLibsodiumWithInitialCounter) - } - val decryptedUsingLibsodium = Stream.chacha20Xor(encryptedUsingLibsodium, nonce, key) - assertTrue { - decryptedUsingLibsodium.contentEquals(message) + LibsodiumInitializer.initializeWithCallback { + val message = "This is a cha cha message".encodeToUByteArray() + val nonce = LibsodiumRandom.bufDeterministic(crypto_stream_chacha20_NONCEBYTES, seed) + val key = Stream.chacha20Keygen() + val stream = Stream.chacha20(message.size, nonce, key) + val encryptedManually = message.mapIndexed { index, it -> it xor stream[index] }.toUByteArray() + val encryptedUsingLibsodium = Stream.chacha20Xor(message, nonce, key) + val encryptedUsingLibsodiumWithInitialCounter = Stream.chacha20XorIc(message, nonce, 0U, key) + println(encryptedManually.toHexString()) + println(encryptedUsingLibsodium.toHexString()) + println(encryptedUsingLibsodiumWithInitialCounter.toHexString()) + println(seed.toHexString()) + assertTrue { + encryptedManually.contentEquals(encryptedUsingLibsodium) + } + assertTrue { + encryptedManually.contentEquals(encryptedUsingLibsodiumWithInitialCounter) + } + val decryptedUsingLibsodium = Stream.chacha20Xor(encryptedUsingLibsodium, nonce, key) + assertTrue { + decryptedUsingLibsodium.contentEquals(message) + } } } @Test fun testChaCha20IetfStream() { - val message = "This is a cha cha message".encodeToUByteArray() - val nonce = LibsodiumRandom.bufDeterministic(crypto_stream_chacha20_NONCEBYTES, seed) - val key = Stream.chacha20Keygen() - val encryptedUsingLibsodium = Stream.chacha20IetfXor(message, nonce, key) - val encryptedUsingLibsodiumWithInitialCounter = Stream.chacha20IetfXorIc(message, nonce, 0U, key) - println(encryptedUsingLibsodium.toHexString()) - println(encryptedUsingLibsodiumWithInitialCounter.toHexString()) - assertTrue { - encryptedUsingLibsodium.contentEquals(encryptedUsingLibsodiumWithInitialCounter) - } - val decryptedUsingLibsodium = Stream.chacha20IetfXor(encryptedUsingLibsodium, nonce, key) - assertTrue { - decryptedUsingLibsodium.contentEquals(message) + LibsodiumInitializer.initializeWithCallback { + val message = "This is a cha cha message".encodeToUByteArray() + val nonce = LibsodiumRandom.bufDeterministic(crypto_stream_chacha20_ietf_NONCEBYTES, seed) + val key = Stream.chacha20Keygen() + val encryptedUsingLibsodium = Stream.chacha20IetfXor(message, nonce, key) + val encryptedUsingLibsodiumWithInitialCounter = Stream.chacha20IetfXorIc(message, nonce, 0U, key) + println(encryptedUsingLibsodium.toHexString()) + println(encryptedUsingLibsodiumWithInitialCounter.toHexString()) + assertTrue { + encryptedUsingLibsodium.contentEquals(encryptedUsingLibsodiumWithInitialCounter) + } + val decryptedUsingLibsodium = Stream.chacha20IetfXor(encryptedUsingLibsodium, nonce, key) + println(message.toHexString()) + println(decryptedUsingLibsodium.toHexString()) + assertTrue { + decryptedUsingLibsodium.contentEquals(message) + } } } } diff --git a/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt index d2cdf7f..1bbdf21 100644 --- a/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt +++ b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt @@ -222,6 +222,16 @@ interface JsSodiumInterface { fun crypto_kx_seed_keypair(seed: Uint8Array) : dynamic fun crypto_kx_server_session_keys(serverPublicKey: Uint8Array, serverSecretKey: Uint8Array, clientPublicKey: Uint8Array) : dynamic + // ---- Key exchange end ---- + + // -- Stream ---- + fun crypto_stream_chacha20(outLength: UInt, key: Uint8Array, nonce: Uint8Array) : Uint8Array + fun crypto_stream_chacha20_ietf_xor(message : Uint8Array, nonce: Uint8Array, key: Uint8Array) : Uint8Array + fun crypto_stream_chacha20_ietf_xor_ic(message : Uint8Array, nonce: Uint8Array, initialCounter: UInt, key: Uint8Array) : Uint8Array + fun crypto_stream_chacha20_keygen() : Uint8Array + fun crypto_stream_chacha20_xor(message : Uint8Array, nonce: Uint8Array, key: Uint8Array) : Uint8Array + fun crypto_stream_chacha20_xor_ic(message : Uint8Array, nonce: Uint8Array, initialCounter: UInt, key: Uint8Array) : Uint8Array + diff --git a/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/stream/Stream.kt b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/stream/Stream.kt new file mode 100644 index 0000000..4845654 --- /dev/null +++ b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/stream/Stream.kt @@ -0,0 +1,82 @@ +package com.ionspin.kotlin.crypto.stream + +import com.ionspin.kotlin.crypto.getSodium +import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray +import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array + +actual object Stream { + actual fun chacha20(clen: Int, nonce: UByteArray, key: UByteArray): UByteArray { + //Note, unlike the other ones, here the positions of key and nonce are reversed. + val result = getSodium().crypto_stream_chacha20(clen.toUInt(), key.toUInt8Array(), nonce.toUInt8Array()) + + return result.toUByteArray() + } + + actual fun chacha20IetfXor( + message: UByteArray, + nonce: UByteArray, + key: UByteArray + ): UByteArray { + val result = getSodium().crypto_stream_chacha20_ietf_xor( + message.toUInt8Array(), + nonce.toUInt8Array(), + key.toUInt8Array() + ) + + return result.toUByteArray() + } + + actual fun chacha20IetfXorIc( + message: UByteArray, + nonce: UByteArray, + initialCounter: ULong, + key: UByteArray + ): UByteArray { + + val result = getSodium().crypto_stream_chacha20_ietf_xor_ic( + message.toUInt8Array(), + nonce.toUInt8Array(), + initialCounter.toUInt(), + 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 { + val result = getSodium().crypto_stream_chacha20_xor_ic( + message.toUInt8Array(), + nonce.toUInt8Array(), + initialCounter.toUInt(), + key.toUInt8Array() + ) + + + return result.toUByteArray() + } +} diff --git a/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/stream/Stream.kt b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/stream/Stream.kt new file mode 100644 index 0000000..32d17f6 --- /dev/null +++ b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/stream/Stream.kt @@ -0,0 +1,98 @@ +package com.ionspin.kotlin.crypto.stream + +import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodium + +actual object Stream { + actual fun chacha20(clen: Int, nonce: UByteArray, key: UByteArray): UByteArray { + val result = UByteArray(clen) + + sodium.crypto_stream_chacha20(result.asByteArray(), clen.toLong(), nonce.asByteArray(), key.asByteArray()) + + return result + } + + actual fun chacha20IetfXor( + message: UByteArray, + nonce: UByteArray, + key: UByteArray + ): UByteArray { + val result = UByteArray(message.size) + + sodium.crypto_stream_chacha20_ietf_xor( + result.asByteArray(), + message.asByteArray(), + message.size.toLong(), + nonce.asByteArray(), + key.asByteArray() + ) + + return result + } + + actual fun chacha20IetfXorIc( + message: UByteArray, + nonce: UByteArray, + initialCounter: ULong, + key: UByteArray + ): UByteArray { + val result = UByteArray(message.size) + + sodium.crypto_stream_chacha20_ietf_xor_ic( + result.asByteArray(), + message.asByteArray(), + message.size.toLong(), + nonce.asByteArray(), + initialCounter.toLong(), + key.asByteArray() + ) + + return result + } + + actual fun chacha20Keygen(): UByteArray { + val result = UByteArray(crypto_stream_chacha20_KEYBYTES) + + sodium.crypto_stream_chacha20_keygen(result.asByteArray()) + + return result + } + + actual fun chacha20Xor( + message: UByteArray, + nonce: UByteArray, + key: UByteArray + ): UByteArray { + val result = UByteArray(message.size) + + sodium.crypto_stream_chacha20_xor( + result.asByteArray(), + message.asByteArray(), + message.size.toLong(), + nonce.asByteArray(), + key.asByteArray() + ) + + return result + } + + actual fun chacha20XorIc( + message: UByteArray, + nonce: UByteArray, + initialCounter: ULong, + key: UByteArray + ): UByteArray { + val result = UByteArray(message.size) + + sodium.crypto_stream_chacha20_xor_ic( + result.asByteArray(), + message.asByteArray(), + message.size.toLong(), + nonce.asByteArray(), + initialCounter.toLong(), + key.asByteArray() + ) + + + return result + } +}