diff --git a/multiplatform-crypto-delegated/src/commonTest/kotlin/com/ionspin/kotlin/crypto/authenticated/XChaCha20Poly1305Test.kt b/multiplatform-crypto-delegated/src/commonTest/kotlin/com/ionspin/kotlin/crypto/authenticated/XChaCha20Poly1305Test.kt index e5dbe1f..68ccc3e 100644 --- a/multiplatform-crypto-delegated/src/commonTest/kotlin/com/ionspin/kotlin/crypto/authenticated/XChaCha20Poly1305Test.kt +++ b/multiplatform-crypto-delegated/src/commonTest/kotlin/com/ionspin/kotlin/crypto/authenticated/XChaCha20Poly1305Test.kt @@ -7,6 +7,7 @@ import com.ionspin.kotlin.crypto.util.hexColumsPrint import com.ionspin.kotlin.crypto.util.testBlocking import kotlin.test.Ignore import kotlin.test.Test +import kotlin.test.assertFails import kotlin.test.assertTrue /** @@ -189,7 +190,7 @@ class XChaCha20Poly1305Test { @Test fun testStreamingImpl() = testBlocking { Initializer.initialize() - val key = UByteArray(32) { 0U} + val key = UByteArray(32) { 0U } val state = ubyteArrayOf( 0x2DU, 0xDBU, 0xC7U, 0xB2U, 0x03U, 0xBCU, 0xC3U, 0x22U, 0xBDU, 0x0CU, 0xBAU, 0x82U, 0xADU, 0x77U, 0x79U, 0x44U, 0xE6U, 0x8FU, 0xA9U, 0x94U, 0x89U, 0xB1U, 0xDFU, 0xBEU, 0x00U, 0x9FU, 0x69U, 0xECU, 0x21U, 0x88U, 0x47U, 0x55U, @@ -210,12 +211,28 @@ class XChaCha20Poly1305Test { 0xDEU, 0xFBU, 0x5CU, 0x7FU, 0x1CU, 0x26U, 0x32U, 0x2CU, 0x51U, 0xF6U, 0xEFU, 0xC6U, 0x34U, 0xC4U, 0xACU, 0x6CU, 0xE8U, 0xF9U, 0x4BU, 0xABU, 0xA3U, ) - val xcha = XChaCha20Poly1305Delegated(key, state, header) + val encryptor = XChaCha20Poly1305Delegated(key, state, header) + val decryptor = XChaCha20Poly1305Delegated(key, state, header) val data = UByteArray(100) { 0U } - val result = xcha.encrypt(data) - + val result = encryptor.encrypt(data) + val decrypted = decryptor.decrypt(result) + println("Encrypted -----------") + result.hexColumsPrint() + println("Encrypted end -----------") + println("Decrypted -----------") + decrypted.hexColumsPrint() + println("Decrypted end -----------") assertTrue { - expected.contentEquals(result) + expected.contentEquals(result) && decrypted.contentEquals(data) + } + val messedUpTag = result.copyOf() + messedUpTag[messedUpTag.size - 2] = 0U + assertFails { + val decryptorForWrongTag = XChaCha20Poly1305Delegated(key, state, header) + val plaintext = decryptorForWrongTag.decrypt(messedUpTag) + println("Decrypted with wrong tag -----------") + plaintext.hexColumsPrint() + println("Decrypted with wrong tag end -----------") } } } diff --git a/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt b/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt index 039fb13..2cf971b 100644 --- a/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt +++ b/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt @@ -50,6 +50,7 @@ interface JsSodiumInterface { //decrypt fun crypto_secretstream_xchacha20poly1305_init_pull(header: Uint8Array, key: Uint8Array) : dynamic + fun crypto_secretstream_xchacha20poly1305_pull(state: dynamic, ciphertext: Uint8Array, additionalData: Uint8Array) : dynamic } diff --git a/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/authenticated/XChaCha20Poly1305Delegated.kt b/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/authenticated/XChaCha20Poly1305Delegated.kt index abbf48a..a2c1b3e 100644 --- a/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/authenticated/XChaCha20Poly1305Delegated.kt +++ b/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/authenticated/XChaCha20Poly1305Delegated.kt @@ -1,6 +1,8 @@ package com.ionspin.kotlin.crypto.authenticated +import com.ionspin.kotlin.crypto.InvalidTagException import com.ionspin.kotlin.crypto.getSodium +import com.ionspin.kotlin.crypto.util.hexColumsPrint import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array import org.khronos.webgl.Uint8Array @@ -84,7 +86,15 @@ actual class XChaCha20Poly1305Delegated internal actual constructor() { } actual fun decrypt(data: UByteArray, additionalData: UByteArray): UByteArray { - TODO("not implemented yet") + val decryptedWithTag = getSodium().crypto_secretstream_xchacha20poly1305_pull(state, data.toUInt8Array(), additionalData.toUInt8Array()) + val decrypted = decryptedWithTag.message as Uint8Array + val validTag = decryptedWithTag.tag as UInt + + if (validTag != 0U) { + println("Tag validation failed") + throw InvalidTagException() + } + return decrypted.toUByteArray() } diff --git a/multiplatform-crypto-delegated/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/authenticated/XChaCha20Poly1305Delegated.kt b/multiplatform-crypto-delegated/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/authenticated/XChaCha20Poly1305Delegated.kt index e6f584a..dcbd5b2 100644 --- a/multiplatform-crypto-delegated/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/authenticated/XChaCha20Poly1305Delegated.kt +++ b/multiplatform-crypto-delegated/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/authenticated/XChaCha20Poly1305Delegated.kt @@ -2,6 +2,7 @@ package com.ionspin.kotlin.crypto.authenticated import com.goterl.lazycode.lazysodium.SodiumJava import com.goterl.lazycode.lazysodium.interfaces.SecretStream +import com.ionspin.kotlin.crypto.InvalidTagException import com.ionspin.kotlin.crypto.util.hexColumsPrint /** @@ -89,14 +90,18 @@ actual class XChaCha20Poly1305Delegated internal actual constructor() { actual fun decrypt(data: UByteArray, additionalData: UByteArray): UByteArray { val plaintext = ByteArray(data.size - 17) - sodium.crypto_secretstream_xchacha20poly1305_pull( + val validTag = sodium.crypto_secretstream_xchacha20poly1305_pull( state, plaintext, null, - data.sliceArray(0 until 1).asByteArray(), - data.sliceArray(1 until data.size).asByteArray(), - (data.size - 17).toLong(), + null, + data.asByteArray(), + (data.size).toLong(), additionalData.asByteArray(), additionalData.size.toLong() ) + if (validTag != 0) { + println("Tag validation failed") + throw InvalidTagException() + } return plaintext.asUByteArray() } diff --git a/multiplatform-crypto-delegated/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/authenticated/XChaCha20Poly1305Delegated.kt b/multiplatform-crypto-delegated/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/authenticated/XChaCha20Poly1305Delegated.kt index 24f6fca..d3eedeb 100644 --- a/multiplatform-crypto-delegated/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/authenticated/XChaCha20Poly1305Delegated.kt +++ b/multiplatform-crypto-delegated/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/authenticated/XChaCha20Poly1305Delegated.kt @@ -1,6 +1,7 @@ package com.ionspin.kotlin.crypto.authenticated import com.ionspin.kotlin.bignum.integer.util.hexColumsPrint +import com.ionspin.kotlin.crypto.InvalidTagException import kotlinx.cinterop.* import libsodium.* import platform.posix.malloc @@ -127,7 +128,24 @@ actual class XChaCha20Poly1305Delegated internal actual constructor() { } actual fun decrypt(data: UByteArray, additionalData: UByteArray): UByteArray { - TODO("not implemented yet") + val plaintext = UByteArray(data.size - crypto_secretstream_xchacha20poly1305_ABYTES.toInt()) + val plaintextPinned = plaintext.pin() + val validTag = crypto_secretstream_xchacha20poly1305_pull( + state.ptr, + plaintextPinned.addressOf(0), + null, + null, + data.toCValues(), + data.size.convert(), + additionalData.toCValues(), + additionalData.size.convert() + ) + plaintextPinned.unpin() + if (validTag != 0) { + println("Tag validation failed") + throw InvalidTagException() + } + return plaintext }