From e2916d0fe2a94d73484d28320391e1eb24027cb6 Mon Sep 17 00:00:00 2001 From: sergeych Date: Wed, 19 Jun 2024 16:46:32 +0700 Subject: [PATCH] Container started --- .../{AsymmetricKey.kt => Asymmetric.kt} | 99 ++++++++---- .../kotlin/net/sergeych/crypto2/Container.kt | 151 +++++++++++++++++- .../net/sergeych/crypto2/DecryptingKey.kt | 2 +- .../net/sergeych/crypto2/EncryptingKey.kt | 2 +- .../net/sergeych/crypto2/SafeKeyExchange.kt | 7 +- .../net/sergeych/crypto2/SymmetricKey.kt | 26 +-- .../net/sergeych/crypto2/UniversalKey.kt | 8 +- .../net/sergeych/crypto2/UniversalRing.kt | 1 + .../kotlin/net/sergeych/crypto2/WithFill.kt | 37 +++++ src/commonTest/kotlin/ContainerTest.kt | 86 ++++++++++ src/commonTest/kotlin/KeysTest.kt | 12 +- src/commonTest/kotlin/RingTest.kt | 5 + 12 files changed, 360 insertions(+), 76 deletions(-) rename src/commonMain/kotlin/net/sergeych/crypto2/{AsymmetricKey.kt => Asymmetric.kt} (68%) create mode 100644 src/commonMain/kotlin/net/sergeych/crypto2/WithFill.kt create mode 100644 src/commonTest/kotlin/ContainerTest.kt diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/AsymmetricKey.kt b/src/commonMain/kotlin/net/sergeych/crypto2/Asymmetric.kt similarity index 68% rename from src/commonMain/kotlin/net/sergeych/crypto2/AsymmetricKey.kt rename to src/commonMain/kotlin/net/sergeych/crypto2/Asymmetric.kt index c29719d..6932a16 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/AsymmetricKey.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/Asymmetric.kt @@ -7,6 +7,7 @@ import com.ionspin.kotlin.crypto.scalarmult.ScalarMultiplication import kotlinx.serialization.Serializable import kotlinx.serialization.Transient import net.sergeych.bipack.BipackDecoder +import net.sergeych.bipack.BipackEncoder import net.sergeych.crypto2.Asymmetric.Message import net.sergeych.crypto2.Asymmetric.PublicKey import net.sergeych.crypto2.Asymmetric.SecretKey @@ -32,7 +33,7 @@ object Asymmetric { /** * Encrypted message holder. * - * Do not instantiate it directly, use [SecretKey.encrypt], [PublicKey.encryptAnonymously] or [createMessage] + * Do not instantiate it directly, use [PublicKey.encryptMessage], [PublicKey.encryptAnonymousMessage], etc. * instead. Also [SecretKey.decrypt] can be used to decrypt it same as [decrypt] or [decryptWithSenderKey]. * * To successfully decrypt the message, it is necessary to know a sender public key, and non-secret nonce. @@ -42,13 +43,12 @@ object Asymmetric { class Message( private val nonce: UByteArray, private val encryptedMessage: UByteArray, - val senderPublicKey: PublicKey? = null, + val senderPublicKey: PublicKey, ) { /** * Decrypt the message, same as [SecretKey.decrypt] */ fun decrypt(recipientKey: SecretKey): UByteArray { - check(senderPublicKey != null) return decryptWithSenderKey(senderPublicKey, recipientKey) } @@ -58,11 +58,15 @@ object Asymmetric { */ fun decryptWithSenderKey(senderKey: PublicKey, recipientKey: SecretKey): UByteArray { return try { - Box.openEasy(encryptedMessage, nonce, senderKey.keyBytes, recipientKey.keyBytes) + WithFill.decode( + Box.openEasy(encryptedMessage, nonce, senderKey.keyBytes, recipientKey.keyBytes) + ) } catch (_: BoxCorruptedOrTamperedDataException) { throw DecryptionFailedException() } } + + val encoded: UByteArray by lazy { BipackEncoder.encode(this).toUByteArray() } } /** @@ -72,30 +76,27 @@ object Asymmetric { * The authenticated encryption is used, is the message _is successfully decrypted_, it also means that * it was signed by the sender, whose public key is known at the decryption time. * - * When it is important not to provide senders' key, use [PublicKey.encryptAnonymously]. + * When it is important not to provide senders' key, use [PublicKey.encryptAnonymousMessage]. * * @param from the senders' secret key. * @param recipient the recipients' public key. * @param plainData data to encrypt - * @param excludeSenderKey if set to true, senders' public key will not be included in the message. - * In this case, the recipient must know it from other sources to be able to decrypt the message. */ - fun createMessage( + private fun createMessage( from: SecretKey, recipient: PublicKey, plainData: UByteArray, - excludeSenderKey: Boolean = false, + nonce: UByteArray = randomNonce(), ): Message { - val nonce = randomNonce() return Message( nonce, Box.easy(plainData, nonce, recipient.keyBytes, from.keyBytes), - if (excludeSenderKey) null else from.publicKey + from.publicKey ) } /** * The generated key pair. See [generateKeys] */ - data class KeyPair(val secretKey: SecretKey, val senderKey: PublicKey) + data class KeyPair(val secretKey: SecretKey, val publicKey: PublicKey) /** * Generate a new random pair of public and secret keys. @@ -114,11 +115,18 @@ object Asymmetric { val nonceBytesLength = crypto_box_NONCEBYTES /** - * The public key used as the recipient for [Message] (see [SecretKey.encrypt], etc.). It also - * could be used to encrypt anonymous messages with [encryptAnonymously] + * The public key: [encryptMessage] so only a secret key owner can read it. Allows + * anonymous [encryptAnonymousMessage] and signed [encryptMessage] encryption. + * + * Anonymous encryption is very slow in comparison. */ @Serializable class PublicKey(val keyBytes: UByteArray) { + + val tag: KeyTag by lazy { + KeyTag(KeysMagickNumbers.defaultAssymmetric, blake2b(keyBytes)) + } + override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is PublicKey) return false @@ -126,19 +134,57 @@ object Asymmetric { return keyBytes contentEquals other.keyBytes } + override fun hashCode(): Int { + return keyBytes.hashCode() + } + /** * Create an anonymous message that could be decrypted only with the [SecretKey] that corresponds this. * Anonymous message uses one-time secret key, the public part of which is included into the * [Message], so the sender could not be identified. + * + * __Anonymous encryption is much slower__ as it generates new keys every time, use [encryptMessage] + * when possible + * * The authentication is used despite the anonymity, and the fact of the successful decryption * proves that the message was not altered after creation. */ - fun encryptAnonymously(plainData: UByteArray): Message = - createMessage(generateKeys().secretKey, this, plainData) + fun encryptAnonymousMessage(plainData: UByteArray, randomFill: IntRange? = null): Message = + encryptMessage(plainData,randomFill=randomFill) + + /** + * Anonymous encryption, see [encryptAnonymousMessage], to binary data. Sender could not be identified. + */ + @Suppress("unused") + fun encrypt(plainData: UByteArray, randomFill: IntRange? = null): UByteArray = + encryptMessage(plainData, randomFill = randomFill).encoded + + /** + * Universal public-key encryption. Note that message authenticity is guaranteed if the decryption is successful + * whether [senderKey] is provider, the latter only allow to positively identify the sender. + * + * @param plainData data to encrypt + * @param nonce allows specifying exact nonce, default to random (safe) + * @param senderKey key to authenticate sending party. It is safe and much faster to specify it, + * otherwise an anonymous key will be created for each encryption, also safe and anonymous, but slow. + */ + fun encryptMessage( + plainData: UByteArray, + nonce: UByteArray = randomNonce(), + senderKey: SecretKey = randomSecretKey(), + randomFill: IntRange? = null, + ) = createMessage(senderKey, this, WithFill.encode(plainData, randomFill), nonce) + + /** + * Encrypt message using the specified secret key as sender authentication. Recipient, the party having + * [SecretKey] corresponding to this one, will be able to decrypt the message and be sure that [senderKey] + * was the author and the message was not altered. + */ + fun encryptMessage(plainData: UByteArray, + senderKey: SecretKey, + randomFill: IntRange? = null): Message = + createMessage(senderKey, this, WithFill.encode(plainData, randomFill)) - override fun hashCode(): Int { - return keyBytes.hashCode() - } } /** @@ -151,19 +197,10 @@ object Asymmetric { val _cachedPublicKey: PublicKey? = null, ) : DecryptingKey { - /** - * Encrypt the message for [recipient]. The [Message] will include the our [publicKey] - * and thus ready to be decrypted. - * - * The message is authenticated by this secret key. - */ - fun encrypt(plainData: UByteArray, recipient: PublicKey): Message = - createMessage(this, recipient, plainData) - /** * Decrypt with authentication checks the message which must have [Message.senderPublicKey] set. * Use [decryptWithSenderKey] otherwise. Note that the authenticated encryption is always use, even if - * the [PublicKey.encryptAnonymously] was used to create a message, if it is successfully decrypted, + * the [PublicKey.encryptAnonymousMessage] was used to create a message, if it is successfully decrypted, * it is guaranteed that the message was not altered after creation. * * @throws DecryptionFailedException If the message is tampered (changed after creation) or was not intended for us, @@ -213,9 +250,7 @@ object Asymmetric { return message.decrypt(this) } - override val decryptingTag: KeyTag by lazy { - KeyTag(KeysMagickNumbers.defaultAssymmetric, blake2b(publicKey.keyBytes)) - } + override val tag: KeyTag by lazy { publicKey.tag } override val nonceBytesLength: Int get() = 0 diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/Container.kt b/src/commonMain/kotlin/net/sergeych/crypto2/Container.kt index cd6bcf1..7996d1d 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/Container.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/Container.kt @@ -1,9 +1,148 @@ -//package net.sergeych.crypto2 -// -//import kotlinx.serialization.Serializable -// -//@Serializable -//sealed class Container { +package net.sergeych.crypto2 + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient +import net.sergeych.bipack.BipackDecoder +import net.sergeych.bipack.BipackEncoder + +/* +The problem with container is the following. When we encrypt it with asymmetric key, +we provide public key as the recipient. But public key alone is not effective +as it is restricted to anonymous encryption which is very slow. + +We might need an alternative to specify the (sender key,recipient key) pair also. We need a good +solution for it. + + */ + + +@Serializable +sealed class Container { + + class InvalidContainerException : Crypto2Exception("the container is invalid") + + abstract fun decryptWith(keyRing: UniversalRing): UByteArray? + + fun decryptWith(vararg decryptingKeys: DecryptingKey): UByteArray? = + decryptWith(UniversalRing(*decryptingKeys)) + + @Transient + var decryptedData: UByteArray? = null + + val isDecrypted: Boolean get() = decryptedData != null + + @Serializable + @SerialName("1") + class Single(val keyTag: KeyTag, val encryptedMessage: UByteArray) : Container() { + override fun decryptWith(keyRing: UniversalRing): UByteArray? { + decryptedData?.let { return it } + for (k in keyRing) { + if (k.tag == keyTag) { + kotlin.runCatching { k.decrypt(encryptedMessage) }.getOrNull()?.let { + decryptedData = it + return it + } + } + } + return null + } + } + + @Serializable + @SerialName("*") + class Multi(val encryptedKeys: List, val encryptedMessage: UByteArray) : Container() { + @Serializable + class EncryptedKey(val tag: KeyTag, val cipherData: UByteArray) + + private var mainKey: SymmetricKey? = null + + override fun decryptWith(keyRing: UniversalRing): UByteArray? { + decryptedData?.let { return it } + for (key in keyRing) { + val tag = key.tag + for (encryptedKey in encryptedKeys) { + if (tag == encryptedKey.tag) { + kotlin.runCatching { + BipackDecoder.decode( + key.decrypt(encryptedKey.cipherData).toByteArray() + ) + }.getOrNull()?.let { k -> + if (kotlin.runCatching { decryptedData = k.decrypt(encryptedKey.cipherData) }.isFailure) + throw InvalidContainerException() + mainKey = k + } + if (decryptedData != null) return decryptedData + } + } + } + return null + } + } + + + val encoded: UByteArray by lazy { + BipackEncoder.encode(this).toUByteArray() + } + + companion object { + + class Builder internal constructor(private val plainData: UByteArray) { + private val plainKeys = mutableListOf() + private val keyPairs = mutableListOf>() + private var fillRange: IntRange? = null + + fun key(vararg keys: EncryptingKey) { plainKeys.addAll(keys) } + + fun key(vararg pairs: Pair) { + keyPairs.addAll(pairs) + } + + fun key(vararg publicKeys: Asymmetric.PublicKey) { + keyPairs.addAll(publicKeys.map { null to it }) + } + + @Suppress("unused") + fun fill(range: IntRange) { + require(range.first >= 0 ) { "range must be positive"} + fillRange = range + } + + fun build(): Container { + return when( plainKeys.size + keyPairs.size ) { + 0 -> throw IllegalArgumentException("Container needs at least one key") + 1 -> { + plainKeys.firstOrNull()?.let { + Single(it.tag, it.encrypt(plainData, fillRange)) + } ?: run { + val (sk, pk) = keyPairs.first() + Single(pk.tag, pk.encryptMessage(plainData, + senderKey = sk ?: Asymmetric.randomSecretKey(), + randomFill = fillRange).encoded) + } + } + else -> { + TODO("multikey") + } + } + } + } + + fun create(plainData: UByteArray,builder: Builder.()->Unit) = + Builder(plainData).also { it.builder() }.build() + + fun create(plainData: UByteArray, vararg keys: EncryptingKey): Container = + create(plainData) { key(*keys) } + + fun create(plainData: UByteArray, vararg keys: Pair) = + create(plainData) { key(*keys) } + + fun decode(encoded: UByteArray): Container { + return BipackDecoder.decode(encoded.toByteArray()) + } + } + +} // // // /** diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/DecryptingKey.kt b/src/commonMain/kotlin/net/sergeych/crypto2/DecryptingKey.kt index c8d6827..b9d8fcf 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/DecryptingKey.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/DecryptingKey.kt @@ -28,7 +28,7 @@ interface DecryptingKey : NonceBased { fun decryptString(cipherData: UByteArray): String = decrypt(cipherData).decodeFromUByteArray() - val decryptingTag: KeyTag + val tag: KeyTag } diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/EncryptingKey.kt b/src/commonMain/kotlin/net/sergeych/crypto2/EncryptingKey.kt index 66f7df1..fb4b538 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/EncryptingKey.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/EncryptingKey.kt @@ -27,7 +27,7 @@ interface EncryptingKey : NonceBased { fun encrypt(plainText: String,randomFill: IntRange? = null): UByteArray = encrypt(plainText.encodeToUByteArray(),randomFill) - val encryptingTag: KeyTag + val tag: KeyTag fun encryptWithNonce(plainData: UByteArray, nonce: UByteArray, randomFill: IntRange? = null): UByteArray } diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/SafeKeyExchange.kt b/src/commonMain/kotlin/net/sergeych/crypto2/SafeKeyExchange.kt index 2906140..02e0137 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/SafeKeyExchange.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/SafeKeyExchange.kt @@ -47,11 +47,14 @@ class SafeKeyExchange { @Suppress("unused") val sessionTag: UByteArray by lazy { if (!isClient) - blake2b(decryptingTag.tag + encryptingTag.tag) + blake2b(tag.tag + tag.tag) else - blake2b(encryptingTag.tag + decryptingTag.tag) + blake2b(tag.tag + tag.tag) } + override val tag: KeyTag + get() = if( isClient ) sendingKey.tag else receivingKey.tag + override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is SessionKey) return false diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/SymmetricKey.kt b/src/commonMain/kotlin/net/sergeych/crypto2/SymmetricKey.kt index 03e56aa..512a636 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/SymmetricKey.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/SymmetricKey.kt @@ -3,8 +3,6 @@ package net.sergeych.crypto2 import com.ionspin.kotlin.crypto.secretbox.SecretBox import com.ionspin.kotlin.crypto.secretbox.crypto_secretbox_NONCEBYTES import kotlinx.serialization.Serializable -import net.sergeych.bipack.BipackDecoder -import net.sergeych.bipack.BipackEncoder /** * Symmetric key implements authenticated encrypting with random nonce and optional fill. @@ -32,36 +30,18 @@ class SymmetricKey( val nonce: UByteArray, ) - /** - * @suppress - * add some random data to the end of the plain message - */ - @Serializable - data class WithFill( - val data: UByteArray, - val safetyFill: UByteArray? = null, - ) - override fun encryptWithNonce(plainData: UByteArray, nonce: UByteArray, randomFill: IntRange?): UByteArray { require(nonce.size == nonceByteLength) - - val fill = randomFill?.let { - require(it.start >= 0) - randomUBytes(randomInt(it)) - } - val filled = BipackEncoder.encode(WithFill(plainData, fill)) - return SecretBox.easy(filled.toUByteArray(), nonce, keyBytes) + return SecretBox.easy(WithFill.encode(plainData, randomFill), nonce, keyBytes) } override val nonceBytesLength: Int = nonceByteLength - override val encryptingTag by lazy { KeyTag(KeysMagickNumbers.defaultSymmetric,blake2b3l(keyBytes)) } - override val decryptingTag get() = encryptingTag + override val tag by lazy { KeyTag(KeysMagickNumbers.defaultSymmetric,blake2b3l(keyBytes)) } override fun decryptWithNonce(cipherData: UByteArray, nonce: UByteArray): UByteArray = protectDecryption { - BipackDecoder.decode(SecretBox.openEasy(cipherData, nonce, keyBytes).toByteArray()) - .data + WithFill.decode(SecretBox.openEasy(cipherData, nonce, keyBytes)) } override fun equals(other: Any?): Boolean { diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/UniversalKey.kt b/src/commonMain/kotlin/net/sergeych/crypto2/UniversalKey.kt index 5d96a5a..79691de 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/UniversalKey.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/UniversalKey.kt @@ -7,7 +7,7 @@ import kotlinx.serialization.Transient @Serializable sealed class UniversalKey : DecryptingKey { - abstract val tag: KeyTag +// abstract val tag: KeyTag @@ -15,7 +15,7 @@ sealed class UniversalKey : DecryptingKey { @SerialName("sy") data class Symmetric(val key: SymmetricKey) : UniversalKey(), EncryptingKey by key, DecryptingKey by key { @Transient - override val tag: KeyTag = key.encryptingTag + override val tag: KeyTag = key.tag @Transient override val nonceBytesLength: Int = key.nonceBytesLength @@ -28,7 +28,7 @@ sealed class UniversalKey : DecryptingKey { data class Session(val key: SafeKeyExchange.SessionKey) : UniversalKey(), EncryptingKey by key, DecryptingKey by key { @Transient - override val tag: KeyTag = key.encryptingTag + override val tag: KeyTag = key.tag @Transient override val nonceBytesLength: Int = key.nonceBytesLength } @@ -36,7 +36,7 @@ sealed class UniversalKey : DecryptingKey { @Serializable @SerialName("se") data class Secret(val key: Asymmetric.SecretKey) : UniversalKey(), DecryptingKey by key { - override val tag: KeyTag by lazy { key.decryptingTag } + override val tag: KeyTag by lazy { key.tag } override fun toString() = "U.Sec:$tag" } diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/UniversalRing.kt b/src/commonMain/kotlin/net/sergeych/crypto2/UniversalRing.kt index 59509fb..838ceff 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/UniversalRing.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/UniversalRing.kt @@ -8,6 +8,7 @@ class UniversalRing( private val keys: Collection ): Collection by keys { constructor(vararg keys: UniversalKey) : this(keys.toSet()) + constructor(vararg keys: DecryptingKey) : this(keys.map { UniversalKey.from(it) }.toSet()) @Transient val keySet = if( keys is Set ) keys else keys.toSet() diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/WithFill.kt b/src/commonMain/kotlin/net/sergeych/crypto2/WithFill.kt new file mode 100644 index 0000000..34badd4 --- /dev/null +++ b/src/commonMain/kotlin/net/sergeych/crypto2/WithFill.kt @@ -0,0 +1,37 @@ +package net.sergeych.crypto2 + +import kotlinx.serialization.Serializable +import net.sergeych.bipack.BipackDecoder +import net.sergeych.bipack.BipackEncoder +import net.sergeych.crypto2.WithFill.Companion.decode +import net.sergeych.crypto2.WithFill.Companion.encode + +/** + * Utility class to optionally extend a message with random bytes added _before the message bytes_ that + * reduces chances to effective cryptanalysis from the first block. Use + * [encode] and [decode] to process filled data. + */ +@Serializable +class WithFill private constructor( + @Suppress("unused") + val safetyFill: UByteArray = ubyteArrayOf(), + val data: UByteArray, +) { + companion object { + + /** + * Create binary data with specified fill + */ + fun encode(data: UByteArray,range: IntRange? = null) = + BipackEncoder.encode(WithFill(range?.let { + require(range.first >= 0) { "range should not be negative" } + randomUBytes(randomInt(it)) + } ?: ubyteArrayOf(), data)).toUByteArray() + + /** + * extract binary data from filled + */ + fun decode(data: UByteArray): UByteArray = + BipackDecoder.decode(data.toByteArray()).data + } +} \ No newline at end of file diff --git a/src/commonTest/kotlin/ContainerTest.kt b/src/commonTest/kotlin/ContainerTest.kt new file mode 100644 index 0000000..308ae25 --- /dev/null +++ b/src/commonTest/kotlin/ContainerTest.kt @@ -0,0 +1,86 @@ +import com.ionspin.kotlin.crypto.util.encodeToUByteArray +import kotlinx.coroutines.test.runTest +import net.sergeych.crypto2.Asymmetric +import net.sergeych.crypto2.Container +import net.sergeych.crypto2.SymmetricKey +import net.sergeych.crypto2.initCrypto +import kotlin.test.* + +class ContainerTest { + @Test + fun testSingle() = runTest { + initCrypto() + val syk1 = SymmetricKey.random() + val syk2 = SymmetricKey.random() + val data = "sergeych, ohm many.".encodeToUByteArray() + + val c = Container.create(data, syk1) + assertFalse { c.isDecrypted } + val c1 = Container.decode(c.encoded) + assertFalse { c.isDecrypted } + assertIs(c) + + assertNull(c1.decryptWith(syk2)) + val d = c1.decryptWith(syk2, syk1) + assertNotNull(d) + assertContentEquals(data, d) + assertTrue { c1.isDecrypted } + } + + @Test + fun testSinglePair() = runTest { + initCrypto() + val p1 = Asymmetric.generateKeys() + val p2 = Asymmetric.generateKeys() + val p3 = Asymmetric.generateKeys() + val data = "sergeych, ohm many.".encodeToUByteArray() + + val c = Container.create(data, p1.secretKey to p2.publicKey) + assertFalse { c.isDecrypted } + val c1 = Container.decode(c.encoded) + assertFalse { c.isDecrypted } + assertIs(c) + + assertNull(c1.decryptWith(p3.secretKey)) + val d = c1.decryptWith(p3.secretKey, p2.secretKey) + assertNotNull(d) + assertContentEquals(data, d) + assertTrue { c1.isDecrypted } + } + + @Test + fun testSingleAsymmetric() = runTest { + initCrypto() +// val p1 = Asymmetric.generateKeys() + val p2 = Asymmetric.generateKeys() + val p3 = Asymmetric.generateKeys() + val data = "sergeych, ohm many.".encodeToUByteArray() + + val c = Container.create(data) { key(p2.publicKey) } + assertFalse { c.isDecrypted } + val c1 = Container.decode(c.encoded) + assertFalse { c.isDecrypted } + assertIs(c) + + assertNull(c1.decryptWith(p3.secretKey)) + val d = c1.decryptWith(p3.secretKey, p2.secretKey) + assertNotNull(d) + assertContentEquals(data, d) + assertTrue { c1.isDecrypted } + } + + @Test + fun testMultipleSymmetric() = runTest { + initCrypto() + val syk1 = SymmetricKey.random() + val syk2 = SymmetricKey.random() +// val syk3 = SymmetricKey.random() + val data = "Translating the name 'Sergey Chernov' from Russian to archaic Sanskrit would be 'Ramo Krishna'" + .encodeToUByteArray() + + val c = Container.create(data, syk1, syk2) + assertFalse { c.isDecrypted } + val c1 = Container.decode(c.encoded) + assertFalse { c1.isDecrypted } + } +} \ No newline at end of file diff --git a/src/commonTest/kotlin/KeysTest.kt b/src/commonTest/kotlin/KeysTest.kt index 1b18381..a1722ec 100644 --- a/src/commonTest/kotlin/KeysTest.kt +++ b/src/commonTest/kotlin/KeysTest.kt @@ -3,7 +3,6 @@ import com.ionspin.kotlin.crypto.util.encodeToUByteArray import kotlinx.coroutines.test.runTest import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json -import net.sergeych.bipack.BipackEncoder import net.sergeych.crypto2.* import net.sergeych.utools.now import net.sergeych.utools.pack @@ -140,25 +139,24 @@ class KeysTest { val plain = "The fake vaccine kills".encodeToUByteArray() - var m = Asymmetric.createMessage(sk0, pk1, plain) + var m = pk1.encryptMessage(plain, sk1) assertContentEquals(plain, m.decrypt(sk1)) assertThrows { assertContentEquals(plain, m.decrypt(sk2)) } - m = pk2.encryptAnonymously(plain) + m = pk2.encryptAnonymousMessage(plain) assertContentEquals(plain, m.decrypt(sk2)) assertContentEquals(plain, sk2.decrypt(m)) - assertContentEquals(plain, sk2.decrypt(sk1.encrypt(plain, pk2))) +// assertContentEquals(plain, sk2.decrypt(sk1.encrypt(plain, pk2))) assertThrows { assertContentEquals(plain, m.decrypt(sk1)) } - val x1 = BipackEncoder.encode(Asymmetric.createMessage(sk0, pk1, plain)) - val x2 = BipackEncoder.encode(Asymmetric.createMessage(sk0, pk1, plain)) + val x1 = pk1.encryptMessage(plain, sk1).encoded + val x2 = pk1.encryptMessage(plain, sk1).encoded assertFalse { x1 contentEquals x2 } - } @Test fun asymmetricKeySerializationTest() = runTest { diff --git a/src/commonTest/kotlin/RingTest.kt b/src/commonTest/kotlin/RingTest.kt index 19f45e7..d519dcd 100644 --- a/src/commonTest/kotlin/RingTest.kt +++ b/src/commonTest/kotlin/RingTest.kt @@ -52,4 +52,9 @@ class RingTest { assertEquals(r, r2) } + @Test + @Ignore + fun testKeysWithSameTags() { + // it should be able to keep keys with same tags + } } \ No newline at end of file