diff --git a/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/box/BoxTest.kt b/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/box/BoxTest.kt new file mode 100644 index 0000000..e2cc2b7 --- /dev/null +++ b/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/box/BoxTest.kt @@ -0,0 +1,96 @@ +package com.ionspin.kotlin.crypto.box + +import com.ionspin.kotlin.bignum.integer.util.hexColumsPrint +import com.ionspin.kotlin.crypto.LibsodiumInitializer +import com.ionspin.kotlin.crypto.util.encodeToUByteArray +import com.ionspin.kotlin.crypto.util.toHexString +import kotlin.random.Random +import kotlin.random.nextUBytes +import kotlin.test.Test +import kotlin.test.assertFailsWith +import kotlin.test.assertTrue + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 01-Sep-2020 + */ +class BoxTest { + @Test + fun keypairTest() { + LibsodiumInitializer.initializeWithCallback { + val keypair = Box.keypair() + assertTrue { + keypair.publicKey.size == crypto_box_PUBLICKEYBYTES + } + assertTrue { + keypair.secretKey.size == crypto_box_SECRETKEYBYTES + } + } + } + + @Test + fun testBoxEasy() { + val message = "Message message message".encodeToUByteArray() + val senderKeypair = Box.keypair() + val recipientKeypair = Box.keypair() + val messageNonce = Random(0).nextUBytes(crypto_box_NONCEBYTES) + val encrypted = Box.easy(message, messageNonce, recipientKeypair.publicKey, senderKeypair.secretKey) + val decrypted = Box.openEasy(encrypted, messageNonce, senderKeypair.publicKey, recipientKeypair.secretKey) + assertTrue { + decrypted.contentEquals(message) + } + + assertFailsWith() { + val tampered = encrypted.copyOf() + tampered[1] = 0U + Box.openEasy(tampered, messageNonce, senderKeypair.publicKey, recipientKeypair.secretKey) + } + } + + @Test + fun testBoxEasyDetached() { + val message = "Message message message".encodeToUByteArray() + val senderKeypair = Box.keypair() + val recipientKeypair = Box.keypair() + val messageNonce = Random(0).nextUBytes(crypto_box_NONCEBYTES) + val encrypted = Box.detached(message, messageNonce, recipientKeypair.publicKey, senderKeypair.secretKey) + val decrypted = Box.openDetached(encrypted.ciphertext, encrypted.tag, messageNonce, senderKeypair.publicKey, recipientKeypair.secretKey) + assertTrue { + decrypted.contentEquals(message) + } + + assertFailsWith() { + val tampered = encrypted.ciphertext.copyOf() + tampered[1] = 0U + Box.openDetached(tampered, encrypted.tag, messageNonce, senderKeypair.publicKey, recipientKeypair.secretKey) + } + } + + @Test + fun testBeforeNonceAndMessage() { + val message = "Message message message".encodeToUByteArray() + val senderKeypair = Box.keypair() + val recipientKeypair = Box.keypair() + val messageNonce = Random(0).nextUBytes(crypto_box_NONCEBYTES) + val senderComputedSessionKey = Box.beforeNM(recipientKeypair.publicKey, senderKeypair.secretKey) + val recipientComputedSessionKey = Box.beforeNM(senderKeypair.publicKey, recipientKeypair.secretKey) + + assertTrue { + senderComputedSessionKey.contentEquals(recipientComputedSessionKey) + } + val encrypted = Box.easyAfterNM(message, messageNonce, senderComputedSessionKey) + val decrypted = Box.openEasyAfterNM(encrypted, messageNonce, recipientComputedSessionKey) + assertTrue { + decrypted.contentEquals(message) + } + + assertFailsWith() { + val tampered = encrypted.copyOf() + tampered[1] = 0U + Box.openEasyAfterNM(tampered, messageNonce, recipientComputedSessionKey) + } + } + + +} 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 80c3d89..574891f 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 @@ -73,7 +73,7 @@ class SecretStreamTest { assertTrue { decrypted.decryptedData.contentEquals(message) } - assertFailsWith(SecretStreamCorrupedOrTamperedDataException::class) { + assertFailsWith(SecretStreamCorruptedOrTamperedDataException::class) { encrypted[encrypted.size - 5] = 0U val decryptState = SecretStream.xChaCha20Poly1305InitPull(key, stateAndHeader.header) val decrypted = diff --git a/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/box/Box.kt b/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/box/Box.kt index d293594..535c284 100644 --- a/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/box/Box.kt +++ b/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/box/Box.kt @@ -1,5 +1,6 @@ package com.ionspin.kotlin.crypto.box +import com.ionspin.kotlin.crypto.util.toHexString import com.ionspin.kotlin.crypto.util.toPtr import kotlinx.cinterop.convert import kotlinx.cinterop.pin @@ -9,6 +10,8 @@ import libsodium.crypto_box_easy import libsodium.crypto_box_easy_afternm import libsodium.crypto_box_keypair import libsodium.crypto_box_open_detached +import libsodium.crypto_box_open_easy +import libsodium.crypto_box_open_easy_afternm import libsodium.crypto_box_seal import libsodium.crypto_box_seal_open import libsodium.crypto_box_seed_keypair @@ -38,7 +41,6 @@ actual object Box { val secretKey = UByteArray(crypto_box_SECRETKEYBYTES) val publicKeyPinned = publicKey.pin() val secretKeyPinned = secretKey.pin() - val seed: UByteArray = UByteArray(crypto_box_SEEDBYTES) val seedPinned = seed.pin() crypto_box_seed_keypair(publicKeyPinned.toPtr(), secretKeyPinned.toPtr(), seedPinned.toPtr()) publicKeyPinned.unpin() @@ -60,7 +62,7 @@ actual object Box { recipientsPublicKey: UByteArray, sendersSecretKey: UByteArray ): UByteArray { - val ciphertext = UByteArray(message.size - crypto_box_MACBYTES) + val ciphertext = UByteArray(message.size + crypto_box_MACBYTES) val ciphertextPinned = ciphertext.pin() val messagePinned = message.pin() @@ -83,7 +85,7 @@ actual object Box { recipientsPublicKeyPinned.unpin() sendersSecretKeyPinned.unpin() - return message + return ciphertext } /** @@ -99,7 +101,7 @@ actual object Box { sendersPublicKey: UByteArray, recipientsSecretKey: UByteArray ): UByteArray { - val message = UByteArray(ciphertext.size + crypto_box_MACBYTES) + val message = UByteArray(ciphertext.size - crypto_box_MACBYTES) val messagePinned = message.pin() val ciphertextPinned = ciphertext.pin() @@ -107,7 +109,7 @@ actual object Box { val sendersPublicKeyPinned = sendersPublicKey.pin() val recipientsSecretKeyPinned = recipientsSecretKey.pin() - crypto_box_easy( + val validationResult = crypto_box_open_easy( messagePinned.toPtr(), ciphertextPinned.toPtr(), ciphertext.size.convert(), @@ -122,6 +124,10 @@ actual object Box { sendersPublicKeyPinned.unpin() recipientsSecretKeyPinned.unpin() + if (validationResult != 0) { + throw BoxCorruptedOrTamperedDataException() + } + return message } @@ -173,6 +179,8 @@ actual object Box { noncePinned.unpin() precomputedKeyPinned.unpin() + + return ciphertext } @@ -191,7 +199,7 @@ actual object Box { val noncePinned = nonce.pin() val precomputedKeyPinned = precomputedKey.pin() - crypto_box_easy_afternm( + val validationResult = crypto_box_open_easy_afternm( messagePinned.toPtr(), ciphertextPinned.toPtr(), ciphertext.size.convert(), @@ -204,7 +212,11 @@ actual object Box { noncePinned.unpin() precomputedKeyPinned.unpin() - return ciphertext + if (validationResult != 0) { + throw BoxCorruptedOrTamperedDataException() + } + + return message } /** @@ -232,8 +244,8 @@ actual object Box { crypto_box_detached( ciphertextPinned.toPtr(), - messagePinned.toPtr(), tagPinned.toPtr(), + messagePinned.toPtr(), message.size.convert(), noncePinned.toPtr(), recipientsPublicKeyPinned.toPtr(), @@ -246,7 +258,6 @@ actual object Box { noncePinned.unpin() recipientsPublicKeyPinned.unpin() sendersSecretKeyPinned.unpin() - return BoxEncryptedDataAndTag(ciphertext, tag) } @@ -265,23 +276,22 @@ actual object Box { ): UByteArray { val message = UByteArray(ciphertext.size) + val messagePinned = message.pin() val ciphertextPinned = ciphertext.pin() val tagPinned = tag.pin() - - val messagePinned = message.pin() val noncePinned = nonce.pin() val recipientsSecretKeyPinned = recipientsSecretKey.pin() val sendersPublicKeyPinned = sendersPublicKey.pin() - crypto_box_open_detached( + val validationResult = crypto_box_open_detached( messagePinned.toPtr(), ciphertextPinned.toPtr(), tagPinned.toPtr(), - message.size.convert(), + ciphertext.size.convert(), noncePinned.toPtr(), - recipientsSecretKeyPinned.toPtr(), - sendersPublicKeyPinned.toPtr() + sendersPublicKeyPinned.toPtr(), + recipientsSecretKeyPinned.toPtr() ) ciphertextPinned.unpin() @@ -291,6 +301,10 @@ actual object Box { recipientsSecretKeyPinned.unpin() sendersPublicKeyPinned.unpin() + if (validationResult != 0) { + throw BoxCorruptedOrTamperedDataException() + } + return message } @@ -318,16 +332,31 @@ actual object Box { actual fun sealOpen(ciphertext: UByteArray, recipientsSecretKey: UByteArray): UByteArray { val message = UByteArray(ciphertext.size - crypto_box_SEALBYTES) + val senderPublicKey = UByteArray(crypto_box_SEALBYTES) { + message[ciphertext.size - crypto_box_SEALBYTES + it - 1] + } + val senderPublicKeyPinned = senderPublicKey.pin() val messagePinned = message.pin() val ciphertextPinned = ciphertext.pin() val recipientsSecretKeyPinned = recipientsSecretKey.pin() - crypto_box_seal_open(messagePinned.toPtr(), ciphertextPinned.toPtr(), recipientsSecretKeyPinned.toPtr()) + val validationResult = crypto_box_seal_open( + messagePinned.toPtr(), + ciphertextPinned.toPtr(), + ciphertext.size.convert(), + senderPublicKeyPinned.toPtr(), + recipientsSecretKeyPinned.toPtr() + ) messagePinned.unpin() ciphertextPinned.unpin() + senderPublicKeyPinned.unpin() recipientsSecretKeyPinned.unpin() + if (validationResult != 0) { + throw BoxCorruptedOrTamperedDataException() + } + return message } 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 index 58b9882..b0da444 100644 --- 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 @@ -1,6 +1,5 @@ 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 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 b0df283..ce04cf0 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 @@ -116,7 +116,7 @@ actual object SecretStream { associatedDataPinned?.unpin() tagPinned.unpin() if (validationResult != 0) { - throw SecretStreamCorrupedOrTamperedDataException() + throw SecretStreamCorruptedOrTamperedDataException() } return DecryptedDataAndTag(message, tag[0]) }