more docs

This commit is contained in:
Sergey Chernov 2024-06-20 18:37:16 +07:00
parent 165cd07353
commit f08653715b
2 changed files with 62 additions and 24 deletions

View File

@ -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 * 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 * 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 * decrypt it. This is sometimes very important to be able to add recipients to the message
* keeping existing recipients you know no keys of. * keeping existing recipients you know no keys of, or update the message when only one of the
* * keys is known.
* See: *
* - [createWith] for more on create a new container * - [createWith] for more on create a new container
* - [addRecipients] and various [plus] operators to add recipients
* - [decryptWith] to decrypt * - [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 @Serializable
sealed class Container { sealed class Container {
@ -83,6 +119,10 @@ sealed class Container {
*/ */
operator fun plus(pair: Pair<Asymmetric.SecretKey, Asymmetric.PublicKey>) = addRecipients { key(pair) } operator fun plus(pair: Pair<Asymmetric.SecretKey, Asymmetric.PublicKey>) = 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 abstract fun updateData(newPlainData: UByteArray,randomFill: IntRange?=null): Container
/** /**
@ -241,17 +281,17 @@ sealed class Container {
* *
* ```kotlin * ```kotlin
* Container.create(plainData) { * Container.create(plainData) {
* // optional: add a random filling from 10 to 20 bytes * // optional: add a random filling from 10 to 20 bytes
* fill( 10 .. 20 ) * 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 * // 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 * // 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. * // to know it was me who added them to this container.
* key(mySecretKey to publicKey2,mySecretKey to publicKey3) * key(mySecretKey to publicKey2,mySecretKey to publicKey3)
* } * }
* ``` * ```
@ -380,17 +420,17 @@ sealed class Container {
* Usage sample: * Usage sample:
* ```kotlin * ```kotlin
* Container.create(plainData) { * Container.create(plainData) {
* // optional: add a random filling from 10 to 20 bytes * // optional: add a random filling from 10 to 20 bytes
* fill( 10 .. 20 ) * 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 * // 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 * // 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. * // to know it was me who added them to this container.
* key(mySecretKey to publicKey2,mySecretKey to publicKey3) * key(mySecretKey to publicKey2,mySecretKey to publicKey3)
* } * }
* ``` * ```
* At least one key should be provided. * At least one key should be provided.

View File

@ -195,11 +195,8 @@ class ContainerTest {
initCrypto() initCrypto()
val syk1 = SymmetricKey.random() val syk1 = SymmetricKey.random()
val syk2 = SymmetricKey.random() val syk2 = SymmetricKey.random()
val syk3 = SymmetricKey.random()
val p1 = Asymmetric.generateKeys() val p1 = Asymmetric.generateKeys()
val p2 = Asymmetric.generateKeys()
val p3 = 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'" val data = "Translating the name 'Sergey Chernov' from Russian to archaic Sanskrit would be 'Ramo Krishna'"
.encodeToUByteArray() .encodeToUByteArray()
@ -273,6 +270,7 @@ class ContainerTest {
val p2 = Asymmetric.generateKeys() val p2 = Asymmetric.generateKeys()
val p3 = Asymmetric.generateKeys() val p3 = Asymmetric.generateKeys()
val p4 = 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'" val data = "Translating the name 'Sergey Chernov' from Russian to archaic Sanskrit would be 'Ramo Krishna'"
.encodeToUByteArray() .encodeToUByteArray()
@ -296,7 +294,7 @@ class ContainerTest {
c.decryptWith(p3.secretKey) c.decryptWith(p3.secretKey)
val data2 = "Cocktails have a delicious, complex taste".encodeToUByteArray() 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 ) expectNotOpen(syk2, syk1, p1.secretKey, p2.secretKey )
expectOpen(data2, syk3, p3.secretKey, p4.secretKey) expectOpen(data2, syk3, p3.secretKey, p4.secretKey)
} }