From 99b9ee5e9dc6be3d7a56df33a0919e3c4111b3e5 Mon Sep 17 00:00:00 2001 From: Ugljesa Jovanovic Date: Sat, 29 Aug 2020 21:53:17 +0200 Subject: [PATCH] Added secretbox functions and constants --- buildSrc/src/main/kotlin/Deps.kt | 5 +- .../secretbox/SecretBox.kt | 30 +++++ .../secretstream/SecretStream.kt | 4 + .../kotlin/crypto/secretbox/SecretBoxTest.kt | 83 ++++++++++++ .../crypto/secretstream/SecretStreamTest.kt | 11 +- .../kotlin/crypto/JsSodiumInterface.kt | 10 ++ .../kotlin/crypto/secretbox/SecretBox.kt | 74 ++++++++++ .../crypto/secretstream/SecretStream.kt | 3 + .../kotlin/crypto/secretbox/SecretBox.kt | 82 +++++++++++ .../{SecretStream.kt => SecretStreamJvm.kt} | 7 +- .../kotlin/crypto/secretbox/SecretBox.kt | 127 ++++++++++++++++++ .../crypto/secretstream/SecretStream.kt | 6 +- .../ionspin/kotlin/crypto/util/SodiumUtil.kt | 8 ++ supported_bindings_list.md | 46 +++---- 14 files changed, 464 insertions(+), 32 deletions(-) create mode 100644 multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/secretbox/SecretBox.kt create mode 100644 multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/secretbox/SecretBoxTest.kt create mode 100644 multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/secretbox/SecretBox.kt create mode 100644 multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/secretbox/SecretBox.kt rename multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/secretstream/{SecretStream.kt => SecretStreamJvm.kt} (90%) create mode 100644 multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/secretbox/SecretBox.kt create mode 100644 multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/util/SodiumUtil.kt diff --git a/buildSrc/src/main/kotlin/Deps.kt b/buildSrc/src/main/kotlin/Deps.kt index c98ede8..e647100 100644 --- a/buildSrc/src/main/kotlin/Deps.kt +++ b/buildSrc/src/main/kotlin/Deps.kt @@ -61,8 +61,9 @@ object Deps { val serialization = "org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:${Versions.kotlinSerialization}" object Npm { - val libsodium = Pair("libsodium-wrappers-sumo", "0.7.6") - val libsodiumWrappers = Pair("libsodium-wrappers-sumo", "file:${getProjectPath()}/multiplatform-crypto-delegated/libsodium-wrappers-sumo-0.7.6.tgz") + val libsodium = Pair("libsodium-wrappers-sumo", "0.7.8") + //val libsodiumWrappers = Pair("libsodium-wrappers-sumo", "file:${getProjectPath()}/multiplatform-crypto-delegated/libsodium-wrappers-sumo-0.7.6.tgz") + val libsodiumWrappers = Pair("libsodium-wrappers-sumo", "0.7.8") } } diff --git a/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/secretbox/SecretBox.kt b/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/secretbox/SecretBox.kt new file mode 100644 index 0000000..23c3d86 --- /dev/null +++ b/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/secretbox/SecretBox.kt @@ -0,0 +1,30 @@ +package com.ionspin.kotlin.crypto.secretbox + +import kotlin.js.JsName + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 29-Aug-2020 + */ + +val crypto_secretbox_KEYBYTES = 32 +val crypto_secretbox_MACBYTES = 16 +val crypto_secretbox_NONCEBYTES = 24 + +class SecretBoxCorruptedOrTamperedDataExceptionOrInvalidKey() : RuntimeException("MAC validation failed. Data is corrupted or tampered with.") + +data class SecretBoxEncryptedDataAndTag( + @JsName("data") + val data: UByteArray, val tag: UByteArray) + +expect object SecretBox { + + fun easy(message : UByteArray, nonce: UByteArray, key: UByteArray) : UByteArray + fun openEasy(ciphertext: UByteArray, nonce: UByteArray, key: UByteArray) : UByteArray + + fun detached(message: UByteArray, nonce: UByteArray, key: UByteArray) : SecretBoxEncryptedDataAndTag + fun openDetached(ciphertext: UByteArray, tag: UByteArray, nonce: UByteArray, key: UByteArray) : UByteArray + + fun keygen() : UByteArray +} diff --git a/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/secretstream/SecretStream.kt b/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/secretstream/SecretStream.kt index 24811d4..c58d137 100644 --- a/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/secretstream/SecretStream.kt +++ b/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/secretstream/SecretStream.kt @@ -4,6 +4,8 @@ package com.ionspin.kotlin.crypto.secretstream * Created by Ugljesa Jovanovic * ugljesa.jovanovic@ionspin.com * on 26-Aug-2020 + * + * This file is named with Jvm suffix because of https://youtrack.jetbrains.com/issue/KT-21186 */ expect class SecretStreamState @@ -20,6 +22,8 @@ val crypto_secretstream_xchacha20poly1305_HEADERBYTES = 24 val crypto_secretstream_xchacha20poly1305_KEYBYTES = 32 val crypto_secretstream_xchacha20poly1305_ABYTES = 17 +class SecretStreamCorrupedOrTamperedDataException() : RuntimeException("MAC validation failed. Data is corrupted or tampered with.") + expect object SecretStream { fun xChaCha20Poly1305InitPush(key: UByteArray) : SecretStreamStateAndHeader diff --git a/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/secretbox/SecretBoxTest.kt b/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/secretbox/SecretBoxTest.kt new file mode 100644 index 0000000..dd3a108 --- /dev/null +++ b/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/secretbox/SecretBoxTest.kt @@ -0,0 +1,83 @@ +package com.ionspin.kotlin.crypto.secretbox + +import com.ionspin.kotlin.crypto.LibsodiumInitializer +import com.ionspin.kotlin.crypto.util.encodeToUByteArray +import com.ionspin.kotlin.crypto.util.toHexString +import kotlin.test.Test +import kotlin.test.assertFailsWith +import kotlin.test.assertTrue + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 29-Aug-2020 + */ +class SecretBoxTest { + + @Test + fun secretBoxTestEasy() { + LibsodiumInitializer.initializeWithCallback { + val message = ("Ladies and Gentlemen of the class of '99: If I could offer you " + + "only one tip for the future, sunscreen would be it.").encodeToUByteArray() + + + val key = ubyteArrayOf( + 0x80U, 0x81U, 0x82U, 0x83U, 0x84U, 0x85U, 0x86U, 0x87U, + 0x88U, 0x89U, 0x8aU, 0x8bU, 0x8cU, 0x8dU, 0x8eU, 0x8fU, + 0x90U, 0x91U, 0x92U, 0x93U, 0x94U, 0x95U, 0x96U, 0x97U, + 0x98U, 0x99U, 0x9aU, 0x9bU, 0x9cU, 0x9dU, 0x9eU, 0x9fU, + ) + + val nonce = ubyteArrayOf( + 0x40U, 0x41U, 0x42U, 0x43U, 0x44U, 0x45U, 0x46U, 0x47U, + 0x48U, 0x49U, 0x4aU, 0x4bU, 0x4cU, 0x4dU, 0x4eU, 0x4fU, + 0x50U, 0x51U, 0x52U, 0x53U, 0x54U, 0x55U, 0x56U, 0x57U, + ) + + val encrypted = SecretBox.easy(message, nonce, key) + val decrypted = SecretBox.openEasy(encrypted, nonce, key) + assertTrue { decrypted.contentEquals(message) } + assertFailsWith(SecretBoxCorruptedOrTamperedDataExceptionOrInvalidKey::class) { + val tamperedTag = encrypted.copyOf() + tamperedTag[2] = 0U + SecretBox.openEasy(tamperedTag, nonce, key) + } + } + + + } + + @Test + fun secretBoxTestDetached() { + LibsodiumInitializer.initializeWithCallback { + val message = ("Ladies and Gentlemen of the class of '99: If I could offer you " + + "only one tip for the future, sunscreen would be it.").encodeToUByteArray() + + + val key = ubyteArrayOf( + 0x80U, 0x81U, 0x82U, 0x83U, 0x84U, 0x85U, 0x86U, 0x87U, + 0x88U, 0x89U, 0x8aU, 0x8bU, 0x8cU, 0x8dU, 0x8eU, 0x8fU, + 0x90U, 0x91U, 0x92U, 0x93U, 0x94U, 0x95U, 0x96U, 0x97U, + 0x98U, 0x99U, 0x9aU, 0x9bU, 0x9cU, 0x9dU, 0x9eU, 0x9fU, + ) + + val nonce = ubyteArrayOf( + 0x40U, 0x41U, 0x42U, 0x43U, 0x44U, 0x45U, 0x46U, 0x47U, + 0x48U, 0x49U, 0x4aU, 0x4bU, 0x4cU, 0x4dU, 0x4eU, 0x4fU, + 0x50U, 0x51U, 0x52U, 0x53U, 0x54U, 0x55U, 0x56U, 0x57U, + ) + + println("Debug") + val encrypted = SecretBox.detached(message, nonce, key) + val decrypted = SecretBox.openDetached(encrypted.data, encrypted.tag, nonce, key) + assertTrue { decrypted.contentEquals(message) } + assertFailsWith(SecretBoxCorruptedOrTamperedDataExceptionOrInvalidKey::class) { + val tamperedTag = encrypted.tag.copyOf() + tamperedTag[2] = 0U + SecretBox.openDetached(encrypted.data, tamperedTag, nonce, key) + } + } + + + } +} diff --git a/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/secretstream/SecretStreamTest.kt b/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/secretstream/SecretStreamTest.kt index 7fc9226..b26dc58 100644 --- a/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/secretstream/SecretStreamTest.kt +++ b/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/secretstream/SecretStreamTest.kt @@ -5,6 +5,7 @@ import com.ionspin.kotlin.crypto.LibsodiumInitializer import com.ionspin.kotlin.crypto.util.encodeToUByteArray import com.ionspin.kotlin.crypto.util.testBlocking import kotlin.test.Test +import kotlin.test.assertFailsWith import kotlin.test.assertTrue /** @@ -71,7 +72,12 @@ class SecretStreamTest { decrypted.decryptedData.hexColumsPrint() assertTrue { decrypted.decryptedData.contentEquals(message) - + } + assertFailsWith(SecretStreamCorrupedOrTamperedDataException::class) { + encrypted[encrypted.size - 5] = 0U + val decryptState = SecretStream.xChaCha20Poly1305InitPull(key, stateAndHeader.header) + val decrypted = + SecretStream.xChaCha20Poly1305Pull(decryptState.state, encrypted, ubyteArrayOf()) } @@ -80,7 +86,8 @@ class SecretStreamTest { } - +// TODO modify nonce in state so we can have reproducible tests, theres already a similar way of doing this +// in crypto delegated project XChaCha20Poly1305 test expect fun modifyState(state: SecretStreamState, forceNonce: UByteArray) 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 aa1711f..8e456a6 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 @@ -61,6 +61,16 @@ interface JsSodiumInterface { fun crypto_secretstream_xchacha20poly1305_keygen() : Uint8Array fun crypto_secretstream_xchacha20poly1305_rekey(state: dynamic) + // ---- SecretBox ---- + fun crypto_secretbox_detached(message: Uint8Array, nonce: Uint8Array, key: Uint8Array) : dynamic + fun crypto_secretbox_easy(message: Uint8Array, nonce: Uint8Array, key: Uint8Array) : Uint8Array + fun crypto_secretbox_keygen() : Uint8Array + fun crypto_secretbox_open_detached(ciphertext : Uint8Array, tag : Uint8Array, nonce: Uint8Array, key: Uint8Array) : dynamic + fun crypto_secretbox_open_easy(ciphertext : Uint8Array, nonce: Uint8Array, key: Uint8Array) : dynamic + + + // ---- SecretBox End ---- + //util fun memzero(array: Uint8Array) diff --git a/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/secretbox/SecretBox.kt b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/secretbox/SecretBox.kt new file mode 100644 index 0000000..4ff9188 --- /dev/null +++ b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/secretbox/SecretBox.kt @@ -0,0 +1,74 @@ +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 +import org.khronos.webgl.Uint8Array + +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 as Uint8Array).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 as Uint8Array).toUByteArray(), + (result.mac as Uint8Array).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 as Uint8Array).toUByteArray() + } catch (error: Throwable) { + throw SecretBoxCorruptedOrTamperedDataExceptionOrInvalidKey() + } + + } + + actual fun keygen(): UByteArray { + return getSodium().crypto_secretbox_keygen().toUByteArray() + } + +} diff --git a/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/secretstream/SecretStream.kt b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/secretstream/SecretStream.kt index 82b0a7c..9c09c34 100644 --- a/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/secretstream/SecretStream.kt +++ b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/com/ionspin/kotlin/crypto/secretstream/SecretStream.kt @@ -40,6 +40,9 @@ actual object SecretStream { val dataAndTag = getSodium().crypto_secretstream_xchacha20poly1305_pull( state, ciphertext.toUInt8Array(), additionalData.toUInt8Array() ) + if (dataAndTag == false) { + throw SecretStreamCorrupedOrTamperedDataException() + } return DecryptedDataAndTag((dataAndTag.message as Uint8Array).toUByteArray(), dataAndTag.tag) } diff --git a/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/secretbox/SecretBox.kt b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/secretbox/SecretBox.kt new file mode 100644 index 0000000..8f113e6 --- /dev/null +++ b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/secretbox/SecretBox.kt @@ -0,0 +1,82 @@ +package com.ionspin.kotlin.crypto.secretbox + +import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodium + +actual object SecretBox { + actual fun easy(message: UByteArray, nonce: UByteArray, key: UByteArray): UByteArray { + val ciphertext = UByteArray(message.size + crypto_secretbox_MACBYTES) + sodium.crypto_secretbox_easy( + ciphertext.asByteArray(), + message.asByteArray(), + message.size.toLong(), + nonce.asByteArray(), + key.asByteArray() + ) + return ciphertext + } + + actual fun openEasy( + ciphertext: UByteArray, + nonce: UByteArray, + key: UByteArray + ): UByteArray { + val decrypted = UByteArray(ciphertext.size - crypto_secretbox_MACBYTES) + val validationResult = sodium.crypto_secretbox_open_easy( + decrypted.asByteArray(), + ciphertext.asByteArray(), + ciphertext.size.toLong(), + nonce.asByteArray(), + key.asByteArray() + ) + if (validationResult != 0) { + throw SecretBoxCorruptedOrTamperedDataExceptionOrInvalidKey() + } + return decrypted + } + + actual fun detached( + message: UByteArray, + nonce: UByteArray, + key: UByteArray + ): SecretBoxEncryptedDataAndTag { + val ciphertext = UByteArray(message.size) + val authenticationTag = UByteArray(crypto_secretbox_MACBYTES) + sodium.crypto_secretbox_detached( + ciphertext.asByteArray(), + authenticationTag.asByteArray(), + message.asByteArray(), + message.size.toLong(), + nonce.asByteArray(), + key.asByteArray() + ) + return SecretBoxEncryptedDataAndTag(ciphertext, authenticationTag) + } + + actual fun openDetached( + ciphertext: UByteArray, + tag: UByteArray, + nonce: UByteArray, + key: UByteArray + ): UByteArray { + val message = UByteArray(ciphertext.size) + val validationResult = sodium.crypto_secretbox_open_detached( + message.asByteArray(), + ciphertext.asByteArray(), + tag.asByteArray(), + ciphertext.size.toLong(), + nonce.asByteArray(), + key.asByteArray() + ) + if (validationResult != 0) { + throw SecretBoxCorruptedOrTamperedDataExceptionOrInvalidKey() + } + return message + } + + actual fun keygen() : UByteArray { + val generatedKey = UByteArray(crypto_secretbox_KEYBYTES) + sodium.crypto_secretbox_keygen(generatedKey.asByteArray()) + return generatedKey + } + +} diff --git a/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/secretstream/SecretStream.kt b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/secretstream/SecretStreamJvm.kt similarity index 90% rename from multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/secretstream/SecretStream.kt rename to multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/secretstream/SecretStreamJvm.kt index ab32a6e..d603555 100644 --- a/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/secretstream/SecretStream.kt +++ b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/secretstream/SecretStreamJvm.kt @@ -49,7 +49,7 @@ actual object SecretStream { ): DecryptedDataAndTag { val result = UByteArray(ciphertext.size - crypto_secretstream_xchacha20poly1305_ABYTES) val tagArray = UByteArray(1) { 0U } - sodium.crypto_secretstream_xchacha20poly1305_pull( + val validationResult = sodium.crypto_secretstream_xchacha20poly1305_pull( state, result.asByteArray(), null, @@ -59,11 +59,14 @@ actual object SecretStream { additionalData.asByteArray(), additionalData.size.toLong() ) + if (validationResult != 0) { + throw SecretStreamCorrupedOrTamperedDataException() + } return DecryptedDataAndTag(result, tagArray[0]) } actual fun xChaCha20Poly1305Keygen(): UByteArray { - val generatedKey = UByteArray(crypto_aead_xchacha20poly1305_ietf_KEYBYTES) + val generatedKey = UByteArray(crypto_secretstream_xchacha20poly1305_KEYBYTES) sodium.crypto_secretstream_xchacha20poly1305_keygen(generatedKey.asByteArray()) return generatedKey } diff --git a/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/secretbox/SecretBox.kt b/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/secretbox/SecretBox.kt new file mode 100644 index 0000000..58b9882 --- /dev/null +++ b/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/secretbox/SecretBox.kt @@ -0,0 +1,127 @@ +package com.ionspin.kotlin.crypto.secretbox + +import com.ionspin.kotlin.crypto.secretstream.SecretStreamCorrupedOrTamperedDataException +import com.ionspin.kotlin.crypto.util.toPtr +import kotlinx.cinterop.convert +import kotlinx.cinterop.pin +import libsodium.crypto_secretbox_detached +import libsodium.crypto_secretbox_easy +import libsodium.crypto_secretbox_keygen +import libsodium.crypto_secretbox_open_detached +import libsodium.crypto_secretbox_open_easy + +actual object SecretBox { + actual fun easy(message: UByteArray, nonce: UByteArray, key: UByteArray): UByteArray { + val ciphertext = UByteArray(message.size + crypto_secretbox_MACBYTES) + val ciphertextPinned = ciphertext.pin() + val messagePinned = message.pin() + val noncePinned = nonce.pin() + val keyPinned = key.pin() + crypto_secretbox_easy( + ciphertextPinned.toPtr(), + messagePinned.toPtr(), + message.size.convert(), + noncePinned.toPtr(), + keyPinned.toPtr() + ) + ciphertextPinned.unpin() + messagePinned.unpin() + noncePinned.unpin() + keyPinned.unpin() + return ciphertext + } + + actual fun openEasy( + ciphertext: UByteArray, + nonce: UByteArray, + key: UByteArray + ): UByteArray { + val message = UByteArray(ciphertext.size - crypto_secretbox_MACBYTES) + val messagePinned = message.pin() + val ciphertextPinned = ciphertext.pin() + val noncePinned = nonce.pin() + val keyPinned = key.pin() + val verificationResult = crypto_secretbox_open_easy( + messagePinned.toPtr(), + ciphertextPinned.toPtr(), + ciphertext.size.convert(), + noncePinned.toPtr(), + keyPinned.toPtr() + ) + ciphertextPinned.unpin() + messagePinned.unpin() + noncePinned.unpin() + keyPinned.unpin() + if (verificationResult != 0) { + throw SecretBoxCorruptedOrTamperedDataExceptionOrInvalidKey() + } + return message + } + + actual fun detached( + message: UByteArray, + nonce: UByteArray, + key: UByteArray + ): SecretBoxEncryptedDataAndTag { + val ciphertext = UByteArray(message.size) + val authenticationTag = UByteArray(crypto_secretbox_MACBYTES) + val ciphertextPinned = ciphertext.pin() + val authenticationTagPinned = authenticationTag.pin() + val messagePinned = message.pin() + val noncePinned = nonce.pin() + val keyPinned = key.pin() + crypto_secretbox_detached( + ciphertextPinned.toPtr(), + authenticationTagPinned.toPtr(), + messagePinned.toPtr(), + message.size.convert(), + noncePinned.toPtr(), + keyPinned.toPtr() + ) + ciphertextPinned.unpin() + authenticationTagPinned.unpin() + messagePinned.unpin() + noncePinned.unpin() + keyPinned.unpin() + return SecretBoxEncryptedDataAndTag(ciphertext, authenticationTag) + } + + actual fun openDetached( + ciphertext: UByteArray, + tag: UByteArray, + nonce: UByteArray, + key: UByteArray + ): UByteArray { + val message = UByteArray(ciphertext.size) + val messagePinned = message.pin() + val ciphertextPinned = ciphertext.pin() + val tagPinned = tag.pin() + val noncePinned = nonce.pin() + val keyPinned = key.pin() + val verificationResult = crypto_secretbox_open_detached( + messagePinned.toPtr(), + ciphertextPinned.toPtr(), + tagPinned.toPtr(), + ciphertext.size.convert(), + noncePinned.toPtr(), + keyPinned.toPtr() + ) + ciphertextPinned.unpin() + messagePinned.unpin() + noncePinned.unpin() + keyPinned.unpin() + if (verificationResult != 0) { + throw SecretBoxCorruptedOrTamperedDataExceptionOrInvalidKey() + } + return message + } + + actual fun keygen() :UByteArray { + val generatedKey = UByteArray(crypto_secretbox_KEYBYTES) + val generatedKeyPinned = generatedKey.pin() + crypto_secretbox_keygen(generatedKeyPinned.toPtr()) + generatedKeyPinned.unpin() + return generatedKey + } + +} diff --git a/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/secretstream/SecretStream.kt b/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/secretstream/SecretStream.kt index 529c1be..3df6325 100644 --- a/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/secretstream/SecretStream.kt +++ b/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/secretstream/SecretStream.kt @@ -101,7 +101,7 @@ actual object SecretStream { } val tag = UByteArray(1) { 0U } val tagPinned = tag.pin() - val validTag = crypto_secretstream_xchacha20poly1305_pull( + val validationResult = crypto_secretstream_xchacha20poly1305_pull( state.ptr, messagePinned.toPtr(), null, @@ -115,8 +115,8 @@ actual object SecretStream { messagePinned.unpin() additionalDataPinned?.unpin() tagPinned.unpin() - if (validTag != 0) { - throw RuntimeException("Invalid tag") + if (validationResult != 0) { + throw SecretStreamCorrupedOrTamperedDataException() } return DecryptedDataAndTag(message, tag[0]) } diff --git a/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/util/SodiumUtil.kt b/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/util/SodiumUtil.kt new file mode 100644 index 0000000..d30db27 --- /dev/null +++ b/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/util/SodiumUtil.kt @@ -0,0 +1,8 @@ +package com.ionspin.kotlin.crypto.util + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 29-Aug-2020 + */ +//fun randomBytesBuf() diff --git a/supported_bindings_list.md b/supported_bindings_list.md index eb7f223..f46df98 100644 --- a/supported_bindings_list.md +++ b/supported_bindings_list.md @@ -102,19 +102,19 @@ | crypto_scalarmult_base | | | crypto_scalarmult_ristretto255 | | | crypto_scalarmult_ristretto255_base | | -| crypto_secretbox_detached | | -| crypto_secretbox_easy | | -| crypto_secretbox_keygen | | -| crypto_secretbox_open_detached | | -| crypto_secretbox_open_easy | | -| crypto_secretstream_xchacha20poly1305_init_pull | :heavy_check_mark: | DONE -| crypto_secretstream_xchacha20poly1305_init_push | :heavy_check_mark: | DONE -| crypto_secretstream_xchacha20poly1305_keygen | :heavy_check_mark: | DONE -| crypto_secretstream_xchacha20poly1305_pull | :heavy_check_mark: | DONE -| crypto_secretstream_xchacha20poly1305_push | :heavy_check_mark: | DONE -| crypto_secretstream_xchacha20poly1305_rekey | :heavy_check_mark: | DONE -| crypto_shorthash |:heavy_check_mark: | DONE -| crypto_shorthash_keygen | :heavy_check_mark: | DONE +| crypto_secretbox_detached | :heavy_check_mark: | +| crypto_secretbox_easy | :heavy_check_mark: | +| crypto_secretbox_keygen | :heavy_check_mark: | +| crypto_secretbox_open_detached | :heavy_check_mark: | +| crypto_secretbox_open_easy | :heavy_check_mark: | +| crypto_secretstream_xchacha20poly1305_init_pull | :heavy_check_mark: | +| crypto_secretstream_xchacha20poly1305_init_push | :heavy_check_mark: | +| crypto_secretstream_xchacha20poly1305_keygen | :heavy_check_mark: | +| crypto_secretstream_xchacha20poly1305_pull | :heavy_check_mark: | +| crypto_secretstream_xchacha20poly1305_push | :heavy_check_mark: | +| crypto_secretstream_xchacha20poly1305_rekey | :heavy_check_mark: | +| crypto_shorthash |:heavy_check_mark: | +| crypto_shorthash_keygen | :heavy_check_mark: | | crypto_shorthash_siphashx24 | | | crypto_sign | | | crypto_sign_detached | | @@ -310,10 +310,10 @@ | crypto_scalarmult_ed25519_SCALARBYTES | | | crypto_scalarmult_ristretto255_BYTES | | | crypto_scalarmult_ristretto255_SCALARBYTES | | -| crypto_secretbox_KEYBYTES | | -| crypto_secretbox_MACBYTES | | +| crypto_secretbox_KEYBYTES | :heavy_check_mark: | +| crypto_secretbox_MACBYTES | :heavy_check_mark: | | crypto_secretbox_MESSAGEBYTES_MAX | | -| crypto_secretbox_NONCEBYTES | | +| crypto_secretbox_NONCEBYTES | :heavy_check_mark: | | crypto_secretbox_xchacha20poly1305_KEYBYTES | | | crypto_secretbox_xchacha20poly1305_MACBYTES | | | crypto_secretbox_xchacha20poly1305_MESSAGEBYTES_MAX | | @@ -322,14 +322,14 @@ | crypto_secretbox_xsalsa20poly1305_MACBYTES | | | crypto_secretbox_xsalsa20poly1305_MESSAGEBYTES_MAX | | | crypto_secretbox_xsalsa20poly1305_NONCEBYTES | | -| crypto_secretstream_xchacha20poly1305_ABYTES | | -| crypto_secretstream_xchacha20poly1305_HEADERBYTES | | -| crypto_secretstream_xchacha20poly1305_KEYBYTES | | +| crypto_secretstream_xchacha20poly1305_ABYTES | :heavy_check_mark: | +| crypto_secretstream_xchacha20poly1305_HEADERBYTES | :heavy_check_mark: | +| crypto_secretstream_xchacha20poly1305_KEYBYTES | :heavy_check_mark: | | crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX | | -| crypto_secretstream_xchacha20poly1305_TAG_FINAL | | -| crypto_secretstream_xchacha20poly1305_TAG_MESSAGE | | -| crypto_secretstream_xchacha20poly1305_TAG_PUSH | | -| crypto_secretstream_xchacha20poly1305_TAG_REKEY | | +| crypto_secretstream_xchacha20poly1305_TAG_FINAL | :heavy_check_mark: | +| crypto_secretstream_xchacha20poly1305_TAG_MESSAGE | :heavy_check_mark: | +| crypto_secretstream_xchacha20poly1305_TAG_PUSH | :heavy_check_mark: | +| crypto_secretstream_xchacha20poly1305_TAG_REKEY | :heavy_check_mark: | | crypto_shorthash_BYTES | | | crypto_shorthash_KEYBYTES | | | crypto_shorthash_siphash24_BYTES | |