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,25 +92,34 @@ sealed class Container {
 | 
			
		||||
        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)
 | 
			
		||||
                    }
 | 
			
		||||
                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)
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    is EncryptingKey -> {
 | 
			
		||||
                        key(k)
 | 
			
		||||
                    }
 | 
			
		||||
                        is EncryptingKey -> {
 | 
			
		||||
                            key(k)
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    is UniversalKey.Secret -> {
 | 
			
		||||
                        key(k.key.publicKey)
 | 
			
		||||
                    }
 | 
			
		||||
                        is UniversalKey.Secret -> {
 | 
			
		||||
                            key(k.key.publicKey)
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    else -> {
 | 
			
		||||
                        throw IllegalStateException("unknown key type to convert container: ${k::class.simpleName}")
 | 
			
		||||
                        else -> {
 | 
			
		||||
                            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