working container with adding keys
This commit is contained in:
parent
e2916d0fe2
commit
1a2febe519
@ -5,57 +5,129 @@ import kotlinx.serialization.Serializable
|
|||||||
import kotlinx.serialization.Transient
|
import kotlinx.serialization.Transient
|
||||||
import net.sergeych.bipack.BipackDecoder
|
import net.sergeych.bipack.BipackDecoder
|
||||||
import net.sergeych.bipack.BipackEncoder
|
import net.sergeych.bipack.BipackEncoder
|
||||||
|
import net.sergeych.crypto2.Container.Companion.createWith
|
||||||
|
|
||||||
/*
|
|
||||||
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.
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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:
|
||||||
|
* - [createWith] for more on create a new container
|
||||||
|
* - [addRecipients] and various [plus] operators to add recipients
|
||||||
|
* - [decryptWith] to decrypt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
sealed class Container {
|
sealed class Container {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when container inner structure is bad. It could mean it was altered.
|
||||||
|
*/
|
||||||
class InvalidContainerException : Crypto2Exception("the container is invalid")
|
class InvalidContainerException : Crypto2Exception("the container is invalid")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to decrypt container contents. This function caches decrypted data, so it is ok
|
||||||
|
* to call it more than once.
|
||||||
|
*
|
||||||
|
* @param keyRing a key ring with keys that caller wants to be used
|
||||||
|
* @return decrypted data or null if this ring contains no proper key for it
|
||||||
|
*/
|
||||||
abstract fun decryptWith(keyRing: UniversalRing): UByteArray?
|
abstract fun decryptWith(keyRing: UniversalRing): UByteArray?
|
||||||
|
|
||||||
fun decryptWith(vararg decryptingKeys: DecryptingKey): UByteArray? =
|
/**
|
||||||
decryptWith(UniversalRing(*decryptingKeys))
|
* Attempt to decrypt container contents. This function caches decrypted data, so it is ok
|
||||||
|
* to call it more than once.
|
||||||
|
*
|
||||||
|
* @param keys keys that caller wants to be used to decrypt with
|
||||||
|
* @return decrypted data or null if this ring contains no proper key for it
|
||||||
|
*/
|
||||||
|
fun decryptWith(vararg keys: DecryptingKey): UByteArray? =
|
||||||
|
decryptWith(UniversalRing(*keys))
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
var decryptedData: UByteArray? = null
|
var decryptedData: UByteArray? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the container is already decrypted. It is important, for example, to be sure it is
|
||||||
|
* before adding more keys.
|
||||||
|
*/
|
||||||
val isDecrypted: Boolean get() = decryptedData != null
|
val isDecrypted: Boolean get() = decryptedData != null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @suppress
|
||||||
|
* Single-key variant, to conserve space it does not use the main key logic and just encrypts the data.
|
||||||
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("1")
|
@SerialName("1")
|
||||||
class Single(val keyTag: KeyTag, val encryptedMessage: UByteArray) : Container() {
|
internal class Single(val keyTag: KeyTag, val encryptedMessage: UByteArray) : Container() {
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private var decryptedWithKey: DecryptingKey? = null
|
||||||
|
|
||||||
override fun decryptWith(keyRing: UniversalRing): UByteArray? {
|
override fun decryptWith(keyRing: UniversalRing): UByteArray? {
|
||||||
decryptedData?.let { return it }
|
decryptedData?.let { return it }
|
||||||
for (k in keyRing) {
|
for (k in keyRing) {
|
||||||
if (k.tag == keyTag) {
|
if (k.tag == keyTag) {
|
||||||
kotlin.runCatching { k.decrypt(encryptedMessage) }.getOrNull()?.let {
|
kotlin.runCatching { k.decrypt(encryptedMessage) }.getOrNull()?.let {
|
||||||
decryptedData = it
|
decryptedData = it
|
||||||
|
decryptedWithKey = k
|
||||||
return it
|
return it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal val asOpenMulti: Container by lazy {
|
||||||
|
check(isDecrypted) { "container should be decrypted" }
|
||||||
|
create(decryptedData!!) {
|
||||||
|
alwaysMulti()
|
||||||
|
when (val k = decryptedWithKey!!) {
|
||||||
|
is Asymmetric.SecretKey -> {
|
||||||
|
key(k.publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
is EncryptingKey -> {
|
||||||
|
key(k)
|
||||||
|
}
|
||||||
|
|
||||||
|
is UniversalKey.Secret -> {
|
||||||
|
key(k.key.publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
throw IllegalStateException("unknown key type to convert container: ${k::class.simpleName}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.apply { decryptWith(decryptedWithKey!!) ?: throw Crypto2Exception("internal error in container update (1)") }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @suppress
|
||||||
|
* Implementation of 2+ keys container
|
||||||
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("*")
|
@SerialName("*")
|
||||||
class Multi(val encryptedKeys: List<EncryptedKey>, val encryptedMessage: UByteArray) : Container() {
|
internal class Multi(val encryptedKeys: List<EncryptedKey>, val encryptedMessage: UByteArray) : Container() {
|
||||||
@Serializable
|
@Serializable
|
||||||
class EncryptedKey(val tag: KeyTag, val cipherData: UByteArray)
|
class EncryptedKey(val tag: KeyTag, val cipherData: UByteArray) {
|
||||||
|
constructor(key: EncryptingKey, encodeMainKey: UByteArray) :
|
||||||
|
this(key.tag, key.encrypt(encodeMainKey))
|
||||||
|
|
||||||
private var mainKey: SymmetricKey? = null
|
constructor(sender: Asymmetric.SecretKey?, recipient: Asymmetric.PublicKey, encodeMainKey: UByteArray) :
|
||||||
|
this(
|
||||||
|
recipient.tag,
|
||||||
|
recipient.encryptMessage(
|
||||||
|
encodeMainKey,
|
||||||
|
senderKey = sender ?: Asymmetric.randomSecretKey(),
|
||||||
|
).encoded
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal var mainKey: SymmetricKey? = null
|
||||||
|
|
||||||
override fun decryptWith(keyRing: UniversalRing): UByteArray? {
|
override fun decryptWith(keyRing: UniversalRing): UByteArray? {
|
||||||
decryptedData?.let { return it }
|
decryptedData?.let { return it }
|
||||||
@ -68,7 +140,8 @@ sealed class Container {
|
|||||||
key.decrypt(encryptedKey.cipherData).toByteArray()
|
key.decrypt(encryptedKey.cipherData).toByteArray()
|
||||||
)
|
)
|
||||||
}.getOrNull()?.let { k ->
|
}.getOrNull()?.let { k ->
|
||||||
if (kotlin.runCatching { decryptedData = k.decrypt(encryptedKey.cipherData) }.isFailure)
|
println(k)
|
||||||
|
if (kotlin.runCatching { decryptedData = k.decrypt(encryptedMessage) }.isFailure)
|
||||||
throw InvalidContainerException()
|
throw InvalidContainerException()
|
||||||
mainKey = k
|
mainKey = k
|
||||||
}
|
}
|
||||||
@ -80,61 +153,204 @@ sealed class Container {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun addRecipients(builder: Builder.() -> Unit): Container =
|
||||||
|
if (this is Single) asOpenMulti.addRecipients(builder)
|
||||||
|
else {
|
||||||
|
Builder(this).apply(builder).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun plus(recipient: Asymmetric.PublicKey) = addRecipients { key(recipient) }
|
||||||
|
operator fun plus(recipient: EncryptingKey) = addRecipients { key(recipient) }
|
||||||
|
operator fun plus(pair: Pair<Asymmetric.SecretKey,Asymmetric.PublicKey>) = addRecipients { key(pair) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binary encoded version. It is desirable to include [Container] as an object, though,
|
||||||
|
* especially when using custom serialization (Json, Boss, etc), it is serializable.
|
||||||
|
* Still, if you need it in binary form, this is a shortcut. You can use [decode] or call
|
||||||
|
* [BipackDecoder.decode] to deserialize the binary form.
|
||||||
|
*/
|
||||||
val encoded: UByteArray by lazy {
|
val encoded: UByteArray by lazy {
|
||||||
BipackEncoder.encode(this).toUByteArray()
|
BipackEncoder.encode(this).toUByteArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
class Builder internal constructor(private val plainData: UByteArray) {
|
/**
|
||||||
|
* The builder to create container with various parameters.
|
||||||
|
* Use [create] to create container using a builder. Usage sample:
|
||||||
|
*
|
||||||
|
* ```kotlin
|
||||||
|
* Container.create(plainData) {
|
||||||
|
* // optional: add a random filling from 10 to 20 bytes
|
||||||
|
* fill( 10 .. 20 )
|
||||||
|
*
|
||||||
|
* key(symmetricKey1, symmetricKey2) // add two SymmetricKey recipients
|
||||||
|
*
|
||||||
|
* 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)
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
|
||||||
|
*/
|
||||||
|
class Builder internal constructor(
|
||||||
|
private val plainData: UByteArray,
|
||||||
|
private var parent: Container? = null,
|
||||||
|
) {
|
||||||
|
|
||||||
|
internal constructor(parent: Container) :
|
||||||
|
this(
|
||||||
|
parent.decryptedData ?: throw IllegalStateException("container is not decrypted"),
|
||||||
|
parent
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
private val plainKeys = mutableListOf<EncryptingKey>()
|
private val plainKeys = mutableListOf<EncryptingKey>()
|
||||||
private val keyPairs = mutableListOf<Pair<Asymmetric.SecretKey?,Asymmetric.PublicKey>>()
|
private val keyPairs = mutableListOf<Pair<Asymmetric.SecretKey?, Asymmetric.PublicKey>>()
|
||||||
private var fillRange: IntRange? = null
|
private var fillRange: IntRange? = null
|
||||||
|
|
||||||
fun key(vararg keys: EncryptingKey) { plainKeys.addAll(keys) }
|
/**
|
||||||
|
* Add one or more encrypting keys
|
||||||
|
*/
|
||||||
|
fun key(vararg keys: EncryptingKey) {
|
||||||
|
plainKeys.addAll(keys)
|
||||||
|
}
|
||||||
|
|
||||||
fun key(vararg pairs: Pair<Asymmetric.SecretKey,Asymmetric.PublicKey>) {
|
/**
|
||||||
|
* Add one or more [Asymmetric.SecretKey] as sender authority coupled with [Asymmetric.PublicKey] as
|
||||||
|
* a recipient. This is faster than anonymous usage of [Asymmetric.PublicKey] only
|
||||||
|
*/
|
||||||
|
fun key(vararg pairs: Pair<Asymmetric.SecretKey, Asymmetric.PublicKey>) {
|
||||||
keyPairs.addAll(pairs)
|
keyPairs.addAll(pairs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add one or more public keys as recipients. This is slower than using pairs of sender -> recipient.
|
||||||
|
*/
|
||||||
fun key(vararg publicKeys: Asymmetric.PublicKey) {
|
fun key(vararg publicKeys: Asymmetric.PublicKey) {
|
||||||
keyPairs.addAll(publicKeys.map { null to it })
|
keyPairs.addAll(publicKeys.map { null to it })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Causes random filling of the encrypted message in the specified interval
|
||||||
|
*/
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun fill(range: IntRange) {
|
fun fill(range: IntRange) {
|
||||||
require(range.first >= 0 ) { "range must be positive"}
|
require(range.first >= 0) { "range must be positive" }
|
||||||
fillRange = range
|
fillRange = range
|
||||||
}
|
}
|
||||||
|
|
||||||
fun build(): Container {
|
private var makeMulti = false
|
||||||
return when( plainKeys.size + keyPairs.size ) {
|
|
||||||
0 -> throw IllegalArgumentException("Container needs at least one key")
|
/**
|
||||||
1 -> {
|
* @suppress
|
||||||
plainKeys.firstOrNull()?.let {
|
* will produce multikey internal variant even with only one key. User internally
|
||||||
Single(it.tag, it.encrypt(plainData, fillRange))
|
*/
|
||||||
} ?: run {
|
internal fun alwaysMulti() {
|
||||||
val (sk, pk) = keyPairs.first()
|
makeMulti = true
|
||||||
Single(pk.tag, pk.encryptMessage(plainData,
|
}
|
||||||
senderKey = sk ?: Asymmetric.randomSecretKey(),
|
|
||||||
randomFill = fillRange).encoded)
|
/**
|
||||||
}
|
* Create a Container
|
||||||
|
*/
|
||||||
|
internal fun build(): Container {
|
||||||
|
val countNewKeys = plainKeys.size + keyPairs.size
|
||||||
|
if (parent != null) require(parent is Multi) { "parent container mut be a multikey variant" }
|
||||||
|
return when {
|
||||||
|
countNewKeys == 0 -> throw IllegalArgumentException("Container needs at least one key")
|
||||||
|
countNewKeys == 1 && makeMulti == false && parent == null -> {
|
||||||
|
createSingle()
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
TODO("multikey")
|
val eks: MutableList<Multi.EncryptedKey>
|
||||||
|
val mainKey: SymmetricKey
|
||||||
|
val p = parent
|
||||||
|
if (p != null) {
|
||||||
|
p as Multi
|
||||||
|
eks = p.encryptedKeys.toMutableList()
|
||||||
|
mainKey = p.mainKey ?: throw IllegalStateException("parent container must be decrypted")
|
||||||
|
} else {
|
||||||
|
eks = mutableListOf<Multi.EncryptedKey>()
|
||||||
|
mainKey = SymmetricKey.random()
|
||||||
|
}
|
||||||
|
val encodedMainKey = BipackEncoder.encode(mainKey).toUByteArray()
|
||||||
|
createMulti(eks, encodedMainKey, mainKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createSingle() = 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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createMulti(
|
||||||
|
eks: MutableList<Multi.EncryptedKey>,
|
||||||
|
encodedMainKey: UByteArray,
|
||||||
|
mainKey: SymmetricKey,
|
||||||
|
): Multi {
|
||||||
|
for (k in plainKeys)
|
||||||
|
eks += Multi.EncryptedKey(k, encodedMainKey)
|
||||||
|
for (p in keyPairs) {
|
||||||
|
val (sender, recipient) = p
|
||||||
|
eks += Multi.EncryptedKey(sender, recipient, encodedMainKey)
|
||||||
|
}
|
||||||
|
return Multi(eks, mainKey.encrypt(plainData, fillRange))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun create(plainData: UByteArray,builder: Builder.()->Unit) =
|
/**
|
||||||
|
* Create a container using a [Builder] instance.
|
||||||
|
* Usage sample:
|
||||||
|
* ```kotlin
|
||||||
|
* Container.create(plainData) {
|
||||||
|
* // optional: add a random filling from 10 to 20 bytes
|
||||||
|
* fill( 10 .. 20 )
|
||||||
|
*
|
||||||
|
* key(symmetricKey1, symmetricKey2) // add two SymmetricKey recipients
|
||||||
|
*
|
||||||
|
* 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)
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
* At least one key should be provided.
|
||||||
|
*
|
||||||
|
* @param plainData data to encrypt
|
||||||
|
*/
|
||||||
|
fun create(plainData: UByteArray, builder: Builder.() -> Unit) =
|
||||||
Builder(plainData).also { it.builder() }.build()
|
Builder(plainData).also { it.builder() }.build()
|
||||||
|
|
||||||
fun create(plainData: UByteArray, vararg keys: EncryptingKey): Container =
|
/**
|
||||||
create(plainData) { key(*keys) }
|
* Create container using one or more [EncryptingKey] and a builder, see [create]
|
||||||
|
* for builder usage sample.
|
||||||
|
*/
|
||||||
|
fun createWith(
|
||||||
|
plainData: UByteArray, vararg keys: EncryptingKey,
|
||||||
|
builder: (Builder.() -> Unit)? = null,
|
||||||
|
): Container =
|
||||||
|
create(plainData) { key(*keys); builder?.invoke(this) }
|
||||||
|
|
||||||
fun create(plainData: UByteArray, vararg keys: Pair<Asymmetric.SecretKey,Asymmetric.PublicKey>) =
|
/**
|
||||||
|
* Create the container using one or more `sender to recipient` asymmetric keys and a builder. See [create]
|
||||||
|
* for builder usage sample.
|
||||||
|
*/
|
||||||
|
fun createWith(plainData: UByteArray, vararg keys: Pair<Asymmetric.SecretKey, Asymmetric.PublicKey>) =
|
||||||
create(plainData) { key(*keys) }
|
create(plainData) { key(*keys) }
|
||||||
|
|
||||||
fun decode(encoded: UByteArray): Container {
|
fun decode(encoded: UByteArray): Container {
|
||||||
|
@ -45,6 +45,7 @@ sealed class UniversalKey : DecryptingKey {
|
|||||||
companion object {
|
companion object {
|
||||||
fun from(key: DecryptingKey) =
|
fun from(key: DecryptingKey) =
|
||||||
when (key) {
|
when (key) {
|
||||||
|
is UniversalKey -> key
|
||||||
is Asymmetric.SecretKey -> Secret(key)
|
is Asymmetric.SecretKey -> Secret(key)
|
||||||
is SymmetricKey -> Symmetric(key)
|
is SymmetricKey -> Symmetric(key)
|
||||||
is SafeKeyExchange.SessionKey -> Session(key)
|
is SafeKeyExchange.SessionKey -> Session(key)
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
import com.ionspin.kotlin.crypto.util.encodeToUByteArray
|
import com.ionspin.kotlin.crypto.util.encodeToUByteArray
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import net.sergeych.crypto2.Asymmetric
|
import net.sergeych.crypto2.*
|
||||||
import net.sergeych.crypto2.Container
|
|
||||||
import net.sergeych.crypto2.SymmetricKey
|
|
||||||
import net.sergeych.crypto2.initCrypto
|
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
|
|
||||||
class ContainerTest {
|
class ContainerTest {
|
||||||
@ -14,7 +11,7 @@ class ContainerTest {
|
|||||||
val syk2 = SymmetricKey.random()
|
val syk2 = SymmetricKey.random()
|
||||||
val data = "sergeych, ohm many.".encodeToUByteArray()
|
val data = "sergeych, ohm many.".encodeToUByteArray()
|
||||||
|
|
||||||
val c = Container.create(data, syk1)
|
val c = Container.createWith(data, syk1)
|
||||||
assertFalse { c.isDecrypted }
|
assertFalse { c.isDecrypted }
|
||||||
val c1 = Container.decode(c.encoded)
|
val c1 = Container.decode(c.encoded)
|
||||||
assertFalse { c.isDecrypted }
|
assertFalse { c.isDecrypted }
|
||||||
@ -35,7 +32,7 @@ class ContainerTest {
|
|||||||
val p3 = Asymmetric.generateKeys()
|
val p3 = Asymmetric.generateKeys()
|
||||||
val data = "sergeych, ohm many.".encodeToUByteArray()
|
val data = "sergeych, ohm many.".encodeToUByteArray()
|
||||||
|
|
||||||
val c = Container.create(data, p1.secretKey to p2.publicKey)
|
val c = Container.createWith(data, p1.secretKey to p2.publicKey)
|
||||||
assertFalse { c.isDecrypted }
|
assertFalse { c.isDecrypted }
|
||||||
val c1 = Container.decode(c.encoded)
|
val c1 = Container.decode(c.encoded)
|
||||||
assertFalse { c.isDecrypted }
|
assertFalse { c.isDecrypted }
|
||||||
@ -74,13 +71,125 @@ 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 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'"
|
val data = "Translating the name 'Sergey Chernov' from Russian to archaic Sanskrit would be 'Ramo Krishna'"
|
||||||
.encodeToUByteArray()
|
.encodeToUByteArray()
|
||||||
|
|
||||||
val c = Container.create(data, syk1, syk2)
|
val c = Container.createWith(data, syk1, syk2) {
|
||||||
|
key(p1.secretKey to p3.publicKey)
|
||||||
|
key(p4.publicKey)
|
||||||
|
}
|
||||||
assertFalse { c.isDecrypted }
|
assertFalse { c.isDecrypted }
|
||||||
val c1 = Container.decode(c.encoded)
|
var c1 = Container.decode(c.encoded)
|
||||||
assertFalse { c1.isDecrypted }
|
assertFalse { c1.isDecrypted }
|
||||||
|
|
||||||
|
assertNull(c1.decryptWith(syk3))
|
||||||
|
assertFalse { c1.isDecrypted }
|
||||||
|
|
||||||
|
assertContentEquals(data, c1.decryptWith(syk3, syk1))
|
||||||
|
assertTrue { c1.isDecrypted }
|
||||||
|
|
||||||
|
c1 = Container.decode(c.encoded)
|
||||||
|
assertFalse { c1.isDecrypted }
|
||||||
|
assertNull(c1.decryptWith(p2.secretKey, p1.secretKey))
|
||||||
|
assertContentEquals(data, c1.decryptWith(syk3, p3.secretKey))
|
||||||
|
|
||||||
|
c1 = Container.decode(c.encoded)
|
||||||
|
assertFalse { c1.isDecrypted }
|
||||||
|
assertContentEquals(data, c1.decryptWith(syk3, p4.secretKey))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSingleGrowSymmetric() = runTest {
|
||||||
|
initCrypto()
|
||||||
|
val syk1 = SymmetricKey.random()
|
||||||
|
val syk2 = SymmetricKey.random()
|
||||||
|
val syk3 = SymmetricKey.random()
|
||||||
|
val p1 = 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()
|
||||||
|
|
||||||
|
var c = Container.createWith(data, syk1)
|
||||||
|
|
||||||
|
fun expectOpen(k: DecryptingKey) {
|
||||||
|
val c1 = Container.decode(c.encoded)
|
||||||
|
assertContentEquals(data, c1.decryptWith(k))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun expectNotOpen(k: DecryptingKey) {
|
||||||
|
val c1 = Container.decode(c.encoded)
|
||||||
|
assertNull(c1.decryptWith(k))
|
||||||
|
}
|
||||||
|
|
||||||
|
expectOpen(syk1)
|
||||||
|
expectNotOpen(syk2)
|
||||||
|
expectNotOpen(p3.secretKey)
|
||||||
|
|
||||||
|
c.decryptWith(syk1)
|
||||||
|
assertTrue { c.isDecrypted }
|
||||||
|
assertNotNull(c.decryptedData)
|
||||||
|
c += syk2
|
||||||
|
expectOpen(syk1)
|
||||||
|
expectOpen(syk2)
|
||||||
|
expectNotOpen(syk3)
|
||||||
|
expectNotOpen(p3.secretKey)
|
||||||
|
|
||||||
|
c.decryptWith(syk1)
|
||||||
|
c += p3.publicKey
|
||||||
|
expectOpen(syk1)
|
||||||
|
expectOpen(syk2)
|
||||||
|
expectOpen(p3.secretKey)
|
||||||
|
expectNotOpen(syk3)
|
||||||
|
expectNotOpen(p4.secretKey)
|
||||||
|
|
||||||
|
c.decryptWith(syk1)
|
||||||
|
c += p1.secretKey to p4.publicKey
|
||||||
|
expectOpen(syk1)
|
||||||
|
expectOpen(syk2)
|
||||||
|
expectOpen(p3.secretKey)
|
||||||
|
expectNotOpen(syk3)
|
||||||
|
expectOpen(p4.secretKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSingleGrowAsymmetric() = runTest {
|
||||||
|
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()
|
||||||
|
|
||||||
|
var c = Container.createWith(data, p1.secretKey to p3.publicKey)
|
||||||
|
|
||||||
|
fun expectOpen(k: DecryptingKey) {
|
||||||
|
val c1 = Container.decode(c.encoded)
|
||||||
|
assertContentEquals(data, c1.decryptWith(k))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun expectNotOpen(k: DecryptingKey) {
|
||||||
|
val c1 = Container.decode(c.encoded)
|
||||||
|
assertNull(c1.decryptWith(k))
|
||||||
|
}
|
||||||
|
|
||||||
|
expectNotOpen(syk1)
|
||||||
|
expectOpen(p3.secretKey)
|
||||||
|
|
||||||
|
c.decryptWith(p3.secretKey)
|
||||||
|
|
||||||
|
c += syk1
|
||||||
|
expectOpen(syk1)
|
||||||
|
expectNotOpen(syk2)
|
||||||
|
expectOpen(p3.secretKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user