fix #5 Just created container is decrypted and can be used to add keys, etc.
This commit is contained in:
parent
c0317dda47
commit
a1561bc280
@ -256,4 +256,11 @@ object Asymmetric {
|
||||
get() = 0
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut type: a pair of sender secret key and recipient private key could be used so
|
||||
* simplify such interfaces
|
||||
*/
|
||||
typealias AsymmetricEncryptionPair = Pair<SecretKey?,PublicKey>
|
||||
|
@ -61,11 +61,20 @@ sealed class Container {
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("1")
|
||||
internal class Single(val keyTag: KeyTag, val encryptedMessage: UByteArray) : Container() {
|
||||
internal class Single(
|
||||
val keyTag: KeyTag, val encryptedMessage: UByteArray,
|
||||
@Transient private val creationData: UByteArray? = null,
|
||||
@Transient private val reEncryptionKey: EncryptingKey? = null,
|
||||
@Transient private var encryptionPair: AsymmetricEncryptionPair? = null,
|
||||
) : Container() {
|
||||
|
||||
@Transient
|
||||
private var decryptedWithKey: DecryptingKey? = null
|
||||
|
||||
init {
|
||||
decryptedData = creationData
|
||||
}
|
||||
|
||||
override fun decryptWith(keyRing: UniversalRing): UByteArray? {
|
||||
decryptedData?.let { return it }
|
||||
for (k in keyRing) {
|
||||
@ -83,7 +92,15 @@ sealed class Container {
|
||||
internal val asOpenMulti: Container by lazy {
|
||||
check(isDecrypted) { "container should be decrypted" }
|
||||
create(decryptedData!!) {
|
||||
alwaysMulti()
|
||||
asOpenedMulti()
|
||||
// The encryption key is known if we just created the container
|
||||
if (reEncryptionKey != null)
|
||||
key(reEncryptionKey)
|
||||
else if (encryptionPair != null) {
|
||||
key(encryptionPair!!)
|
||||
} else {
|
||||
// otherwise, we don't know the encryption key and will try to derive it
|
||||
// from the decryption key:
|
||||
when (val k = decryptedWithKey!!) {
|
||||
is Asymmetric.SecretKey -> {
|
||||
key(k.publicKey)
|
||||
@ -101,7 +118,8 @@ sealed class Container {
|
||||
throw IllegalStateException("unknown key type to convert container: ${k::class.simpleName}")
|
||||
}
|
||||
}
|
||||
}.apply { decryptWith(decryptedWithKey!!) ?: throw Crypto2Exception("internal error in container update (1)") }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,7 +129,12 @@ sealed class Container {
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("*")
|
||||
internal class Multi(val encryptedKeys: List<EncryptedKey>, val encryptedMessage: UByteArray) : Container() {
|
||||
internal class Multi(
|
||||
val encryptedKeys: List<EncryptedKey>, val encryptedMessage: UByteArray,
|
||||
@Transient internal var mainKey: SymmetricKey? = null,
|
||||
@Transient internal var knownPlainData: UByteArray? = null,
|
||||
|
||||
) : Container() {
|
||||
@Serializable
|
||||
class EncryptedKey(val tag: KeyTag, val cipherData: UByteArray) {
|
||||
constructor(key: EncryptingKey, encodeMainKey: UByteArray) :
|
||||
@ -127,7 +150,9 @@ sealed class Container {
|
||||
)
|
||||
}
|
||||
|
||||
internal var mainKey: SymmetricKey? = null
|
||||
init {
|
||||
knownPlainData?.let { decryptedData = it }
|
||||
}
|
||||
|
||||
override fun decryptWith(keyRing: UniversalRing): UByteArray? {
|
||||
decryptedData?.let { return it }
|
||||
@ -164,17 +189,22 @@ sealed class Container {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add e key to the __decrypted__ container
|
||||
* Add e key to the __decrypted__ container. The new container is also decrypted so you can add
|
||||
* more keys, etc.
|
||||
*/
|
||||
operator fun plus(recipient: Asymmetric.PublicKey) = addRecipients { key(recipient) }
|
||||
|
||||
/**
|
||||
* Add e key to the __decrypted__ container
|
||||
* Add e key to the __decrypted__ container. The new container is also decrypted so you can add
|
||||
* more keys, etc.
|
||||
*/
|
||||
operator fun plus(recipient: EncryptingKey) = addRecipients { key(recipient) }
|
||||
|
||||
/**
|
||||
* Add e sender -> recipient asymmetric keys pair key to the __decrypted__ container
|
||||
* Add e key to the __decrypted__ container. The new container is also decrypted so you can add
|
||||
* more keys, etc.
|
||||
*/
|
||||
operator fun plus(pair: Pair<Asymmetric.SecretKey,Asymmetric.PublicKey>) = addRecipients { key(pair) }
|
||||
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,
|
||||
@ -222,7 +252,7 @@ sealed class Container {
|
||||
|
||||
|
||||
private val plainKeys = mutableListOf<EncryptingKey>()
|
||||
private val keyPairs = mutableListOf<Pair<Asymmetric.SecretKey?, Asymmetric.PublicKey>>()
|
||||
private val keyPairs = mutableListOf<AsymmetricEncryptionPair>()
|
||||
private var fillRange: IntRange? = null
|
||||
|
||||
/**
|
||||
@ -236,7 +266,7 @@ sealed class Container {
|
||||
* 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>) {
|
||||
fun key(vararg pairs: AsymmetricEncryptionPair) {
|
||||
keyPairs.addAll(pairs)
|
||||
}
|
||||
|
||||
@ -256,14 +286,14 @@ sealed class Container {
|
||||
fillRange = range
|
||||
}
|
||||
|
||||
private var makeMulti = false
|
||||
private var makeOpenedMulti = false
|
||||
|
||||
/**
|
||||
* @suppress
|
||||
* will produce multikey internal variant even with only one key. User internally
|
||||
*/
|
||||
internal fun alwaysMulti() {
|
||||
makeMulti = true
|
||||
internal fun asOpenedMulti() {
|
||||
makeOpenedMulti = true
|
||||
}
|
||||
|
||||
/**
|
||||
@ -274,7 +304,7 @@ sealed class Container {
|
||||
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 -> {
|
||||
countNewKeys == 1 && makeOpenedMulti == false && parent == null -> {
|
||||
createSingle()
|
||||
}
|
||||
|
||||
@ -297,16 +327,20 @@ sealed class Container {
|
||||
}
|
||||
|
||||
private fun createSingle() = plainKeys.firstOrNull()?.let {
|
||||
Single(it.tag, it.encrypt(plainData, fillRange))
|
||||
Single(it.tag, it.encrypt(plainData, fillRange), plainData, reEncryptionKey = it)
|
||||
} ?: run {
|
||||
val (sk, pk) = keyPairs.first()
|
||||
val pair = keyPairs.first()
|
||||
val (sk, pk) = pair
|
||||
Single(
|
||||
pk.tag, pk.encryptMessage(
|
||||
plainData,
|
||||
senderKey = sk ?: Asymmetric.randomSecretKey(),
|
||||
randomFill = fillRange
|
||||
).encoded
|
||||
).encoded,
|
||||
plainData,
|
||||
encryptionPair = pair
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
private fun createMulti(
|
||||
@ -320,7 +354,10 @@ sealed class Container {
|
||||
val (sender, recipient) = p
|
||||
eks += Multi.EncryptedKey(sender, recipient, encodedMainKey)
|
||||
}
|
||||
return Multi(eks, mainKey.encrypt(plainData, fillRange))
|
||||
return if (makeOpenedMulti)
|
||||
Multi(eks, mainKey.encrypt(plainData, fillRange), mainKey, plainData)
|
||||
else
|
||||
Multi(eks, mainKey.encrypt(plainData, fillRange))
|
||||
}
|
||||
}
|
||||
|
||||
@ -363,7 +400,7 @@ sealed class Container {
|
||||
* 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>) =
|
||||
fun createWith(plainData: UByteArray, vararg keys: AsymmetricEncryptionPair) =
|
||||
create(plainData) { key(*keys) }
|
||||
|
||||
fun decode(encoded: UByteArray): Container {
|
||||
|
@ -1,5 +1,7 @@
|
||||
import com.ionspin.kotlin.crypto.util.encodeToUByteArray
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import net.sergeych.crypto2.*
|
||||
import kotlin.test.*
|
||||
|
||||
@ -12,9 +14,9 @@ class ContainerTest {
|
||||
val data = "sergeych, ohm many.".encodeToUByteArray()
|
||||
|
||||
val c = Container.createWith(data, syk1)
|
||||
assertFalse { c.isDecrypted }
|
||||
assertTrue { c.isDecrypted }
|
||||
val c1 = Container.decode(c.encoded)
|
||||
assertFalse { c.isDecrypted }
|
||||
assertFalse { c1.isDecrypted }
|
||||
assertIs<Container.Single>(c)
|
||||
|
||||
assertNull(c1.decryptWith(syk2))
|
||||
@ -33,9 +35,9 @@ class ContainerTest {
|
||||
val data = "sergeych, ohm many.".encodeToUByteArray()
|
||||
|
||||
val c = Container.createWith(data, p1.secretKey to p2.publicKey)
|
||||
assertFalse { c.isDecrypted }
|
||||
assertTrue { c.isDecrypted }
|
||||
val c1 = Container.decode(c.encoded)
|
||||
assertFalse { c.isDecrypted }
|
||||
assertFalse { c1.isDecrypted }
|
||||
assertIs<Container.Single>(c)
|
||||
|
||||
assertNull(c1.decryptWith(p3.secretKey))
|
||||
@ -54,9 +56,10 @@ class ContainerTest {
|
||||
val data = "sergeych, ohm many.".encodeToUByteArray()
|
||||
|
||||
val c = Container.create(data) { key(p2.publicKey) }
|
||||
assertFalse { c.isDecrypted }
|
||||
assertTrue { c.isDecrypted }
|
||||
val c1 = Container.decode(c.encoded)
|
||||
assertFalse { c.isDecrypted }
|
||||
println(Json.encodeToString(c1))
|
||||
assertFalse { c1.isDecrypted }
|
||||
assertIs<Container.Single>(c)
|
||||
|
||||
assertNull(c1.decryptWith(p3.secretKey))
|
||||
|
Loading…
x
Reference in New Issue
Block a user