From f08653715b5e3669d20322c20f323ca8d321c825 Mon Sep 17 00:00:00 2001 From: sergeych Date: Thu, 20 Jun 2024 18:37:16 +0700 Subject: [PATCH] more docs --- .../kotlin/net/sergeych/crypto2/Container.kt | 80 ++++++++++++++----- src/commonTest/kotlin/ContainerTest.kt | 6 +- 2 files changed, 62 insertions(+), 24 deletions(-) diff --git a/src/commonMain/kotlin/net/sergeych/crypto2/Container.kt b/src/commonMain/kotlin/net/sergeych/crypto2/Container.kt index 00cad99..9e0a643 100644 --- a/src/commonMain/kotlin/net/sergeych/crypto2/Container.kt +++ b/src/commonMain/kotlin/net/sergeych/crypto2/Container.kt @@ -12,12 +12,48 @@ import net.sergeych.crypto2.Container.Companion.createWith * Multi-key encrypted container with simple adding new keys function that does not need to * know all existing keys, e.g., you can add recipients to the container data if you can * decrypt it. This is sometimes very important to be able to add recipients to the message - * keeping existing recipients you know no keys of. - * - * See: + * keeping existing recipients you know no keys of, or update the message when only one of the + * keys is known. + * * - [createWith] for more on create a new container - * - [addRecipients] and various [plus] operators to add recipients * - [decryptWith] to decrypt + * - [addRecipients] and various [plus] operators to add recipients + * - [updateData] to change decrypted content for the same recipient keys + * + * Some rules: + * + * When adding public key recipient, it is faster to use your known [Asymmetric.SecretKey], but you + * can stay anonymous by just adding [Asymmetric.PublicKey] only. + * + * Put your data in [SealedBox] if you need to authenticate message origin and timestamp, then put + * the sealed box in the [Container], this will conceal signers from attack. In the case you need to + * prove message origin without disclosing its content, put the [Container] in the [SealedBox]. + * Everybody will see who and when have it signed, but only intended recipients could read it. + * + * Sample: + * ```kotlin + * // create container fpr p3.public key destination using our secret key (for speed) + * var c = Container.createWith(data, p1.secretKey to p3.publicKey) + * + * // imitation of receiving an encrypted container in binary form + * // so it is not decrypted + * c = Container.decode(c.encoded) + * + * // decrypt it with the right key + * c.decryptWith(p3.secretKey) + * + * + * // add more keys to it: 2 symmetric, public anonymous, and secret-to-public pair (faster) + * c = c + symmetricKey1 + symmetricKey2 + herPublicKey + (MySecretKey to hisPublicKey) + * + * // and update data in it (it will be encrypted too), adding random bytes, at least 100 and no + * // more than 200, to make size analysis attack almost impossible + * // in the 100 to 200 + * c = c..updateData(data2, 100..22) + * + * // now we can send it over the network + * sendOVerTheNetwork(c.encoded) + *``` */ @Serializable sealed class Container { @@ -83,6 +119,10 @@ sealed class Container { */ operator fun plus(pair: Pair) = addRecipients { key(pair) } + /** + * Update the data in the decrypted container. It keeps the same set of keys and update + * the data only. + */ abstract fun updateData(newPlainData: UByteArray,randomFill: IntRange?=null): Container /** @@ -241,17 +281,17 @@ sealed class Container { * * ```kotlin * Container.create(plainData) { - * // optional: add a random filling from 10 to 20 bytes - * fill( 10 .. 20 ) + * // optional: add a random filling from 10 to 20 bytes + * fill( 10 .. 20 ) * - * key(symmetricKey1, symmetricKey2) // add two SymmetricKey recipients + * key(symmetricKey1, symmetricKey2) // add two SymmetricKey recipients * - * key(publicKey1) // add a Asymmetric.PublicKey recipient anonymously + * key(publicKey1) // add a Asymmetric.PublicKey recipient anonymously * - * // More interesting: add publicKey2 and publicKey3 recipients using my - * // secret key as authority. IT is faster and allow to owner of the listed public keys - * // to know it was me who added them to this container. - * key(mySecretKey to publicKey2,mySecretKey to publicKey3) + * // More interesting: add publicKey2 and publicKey3 recipients using my + * // secret key as authority. IT is faster and allow to owner of the listed public keys + * // to know it was me who added them to this container. + * key(mySecretKey to publicKey2,mySecretKey to publicKey3) * } * ``` @@ -380,17 +420,17 @@ sealed class Container { * Usage sample: * ```kotlin * Container.create(plainData) { - * // optional: add a random filling from 10 to 20 bytes - * fill( 10 .. 20 ) + * // optional: add a random filling from 10 to 20 bytes + * fill( 10 .. 20 ) * - * key(symmetricKey1, symmetricKey2) // add two SymmetricKey recipients + * key(symmetricKey1, symmetricKey2) // add two SymmetricKey recipients * - * key(publicKey1) // add a Asymmetric.PublicKey recipient anonymously + * key(publicKey1) // add a Asymmetric.PublicKey recipient anonymously * - * // More interesting: add publicKey2 and publicKey3 recipients using my - * // secret key as authority. IT is faster and allow to owner of the listed public keys - * // to know it was me who added them to this container. - * key(mySecretKey to publicKey2,mySecretKey to publicKey3) + * // More interesting: add publicKey2 and publicKey3 recipients using my + * // secret key as authority. IT is faster and allow to owner of the listed public keys + * // to know it was me who added them to this container. + * key(mySecretKey to publicKey2,mySecretKey to publicKey3) * } * ``` * At least one key should be provided. diff --git a/src/commonTest/kotlin/ContainerTest.kt b/src/commonTest/kotlin/ContainerTest.kt index 383b5ad..70dd22e 100644 --- a/src/commonTest/kotlin/ContainerTest.kt +++ b/src/commonTest/kotlin/ContainerTest.kt @@ -195,11 +195,8 @@ class ContainerTest { initCrypto() val syk1 = SymmetricKey.random() val syk2 = SymmetricKey.random() - val syk3 = SymmetricKey.random() val p1 = Asymmetric.generateKeys() - val p2 = Asymmetric.generateKeys() val p3 = Asymmetric.generateKeys() - val p4 = Asymmetric.generateKeys() val data = "Translating the name 'Sergey Chernov' from Russian to archaic Sanskrit would be 'Ramo Krishna'" .encodeToUByteArray() @@ -273,6 +270,7 @@ class ContainerTest { val p2 = Asymmetric.generateKeys() val p3 = Asymmetric.generateKeys() val p4 = Asymmetric.generateKeys() + val p5 = Asymmetric.generateKeys() val data = "Translating the name 'Sergey Chernov' from Russian to archaic Sanskrit would be 'Ramo Krishna'" .encodeToUByteArray() @@ -296,7 +294,7 @@ class ContainerTest { c.decryptWith(p3.secretKey) val data2 = "Cocktails have a delicious, complex taste".encodeToUByteArray() - c = (c + syk3 + (p1.secretKey to p4.publicKey)).updateData(data2) + c = (c + syk3 + p5.publicKey + (p1.secretKey to p4.publicKey)).updateData(data2) expectNotOpen(syk2, syk1, p1.secretKey, p2.secretKey ) expectOpen(data2, syk3, p3.secretKey, p4.secretKey) }