keys refactoring: removed separate UniversalKey, it is now a direct base of any real keys instead of deleted KeyInstance
This commit is contained in:
		
							parent
							
								
									5c97e857fc
								
							
						
					
					
						commit
						46a8b5bc06
					
				@ -4,6 +4,7 @@ import com.ionspin.kotlin.crypto.box.Box
 | 
				
			|||||||
import com.ionspin.kotlin.crypto.box.BoxCorruptedOrTamperedDataException
 | 
					import com.ionspin.kotlin.crypto.box.BoxCorruptedOrTamperedDataException
 | 
				
			||||||
import com.ionspin.kotlin.crypto.box.crypto_box_NONCEBYTES
 | 
					import com.ionspin.kotlin.crypto.box.crypto_box_NONCEBYTES
 | 
				
			||||||
import com.ionspin.kotlin.crypto.scalarmult.ScalarMultiplication
 | 
					import com.ionspin.kotlin.crypto.scalarmult.ScalarMultiplication
 | 
				
			||||||
 | 
					import kotlinx.serialization.SerialName
 | 
				
			||||||
import kotlinx.serialization.Serializable
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
import kotlinx.serialization.Transient
 | 
					import kotlinx.serialization.Transient
 | 
				
			||||||
import net.sergeych.bipack.BipackDecoder
 | 
					import net.sergeych.bipack.BipackDecoder
 | 
				
			||||||
@ -121,7 +122,8 @@ object Asymmetric {
 | 
				
			|||||||
     * Anonymous encryption is very slow in comparison.
 | 
					     * Anonymous encryption is very slow in comparison.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    @Serializable
 | 
					    @Serializable
 | 
				
			||||||
    class PublicKey(override val keyBytes: UByteArray) : BinaryKeyBase(), KeyInstance {
 | 
					    @SerialName("encp")
 | 
				
			||||||
 | 
					    class PublicKey(override val keyBytes: UByteArray) : UniversalKey(), EncryptingKey {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        override val magick: KeysMagickNumber = KeysMagickNumber.defaultAssymmetric
 | 
					        override val magick: KeysMagickNumber = KeysMagickNumber.defaultAssymmetric
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -143,9 +145,14 @@ object Asymmetric {
 | 
				
			|||||||
         * Anonymous encryption, see [encryptAnonymousMessage], to binary data. Sender could not be identified.
 | 
					         * Anonymous encryption, see [encryptAnonymousMessage], to binary data. Sender could not be identified.
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
        @Suppress("unused")
 | 
					        @Suppress("unused")
 | 
				
			||||||
        fun encrypt(plainData: UByteArray, randomFill: IntRange? = null): UByteArray =
 | 
					        override fun encrypt(plainData: UByteArray, randomFill: IntRange?): UByteArray =
 | 
				
			||||||
            encryptMessage(plainData, randomFill = randomFill).encoded
 | 
					            encryptMessage(plainData, randomFill = randomFill).encoded
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        override fun encryptWithNonce(plainData: UByteArray, nonce: UByteArray, randomFill: IntRange?): UByteArray =
 | 
				
			||||||
 | 
					            encryptMessage(plainData, nonce = nonce, randomFill = randomFill).encoded
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        override val nonceBytesLength: Int = Asymmetric.nonceBytesLength
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /**
 | 
					        /**
 | 
				
			||||||
         * Universal public-key encryption. Note that message authenticity is guaranteed if the decryption is successful
 | 
					         * Universal public-key encryption. Note that message authenticity is guaranteed if the decryption is successful
 | 
				
			||||||
         * whether [senderKey] is provider, the latter only allow to positively identify the sender.
 | 
					         * whether [senderKey] is provider, the latter only allow to positively identify the sender.
 | 
				
			||||||
@ -173,19 +180,18 @@ object Asymmetric {
 | 
				
			|||||||
            randomFill: IntRange? = null,
 | 
					            randomFill: IntRange? = null,
 | 
				
			||||||
        ): Message =
 | 
					        ): Message =
 | 
				
			||||||
            createMessage(senderKey, this, WithFill.encode(plainData, randomFill))
 | 
					            createMessage(senderKey, this, WithFill.encode(plainData, randomFill))
 | 
				
			||||||
 | 
					 | 
				
			||||||
        fun toUniversalKey(): UniversalKey.Public = UniversalKey.Public(this)
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * The secret key
 | 
					     * The secret key
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    @Serializable
 | 
					    @Serializable
 | 
				
			||||||
 | 
					    @SerialName("encs")
 | 
				
			||||||
    class SecretKey(
 | 
					    class SecretKey(
 | 
				
			||||||
        override val keyBytes: UByteArray,
 | 
					        override val keyBytes: UByteArray,
 | 
				
			||||||
        @Transient
 | 
					        @Transient
 | 
				
			||||||
        val _cachedPublicKey: PublicKey? = null,
 | 
					        val _cachedPublicKey: PublicKey? = null,
 | 
				
			||||||
    ) : DecryptingKey, BinaryKeyBase() {
 | 
					    ) : DecryptingKey, UniversalKey() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /**
 | 
					        /**
 | 
				
			||||||
         * Decrypt with authentication checks the message which must have [Message.senderPublicKey] set.
 | 
					         * Decrypt with authentication checks the message which must have [Message.senderPublicKey] set.
 | 
				
			||||||
 | 
				
			|||||||
@ -1,31 +0,0 @@
 | 
				
			|||||||
package net.sergeych.crypto2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import kotlinx.serialization.Serializable
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@Serializable
 | 
					 | 
				
			||||||
abstract class BinaryKeyBase() {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    abstract val keyBytes: UByteArray
 | 
					 | 
				
			||||||
    abstract val magick: KeysMagickNumber
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    open val id by lazy { KeyId(magick, keyBytes) }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun equals(other: Any?): Boolean {
 | 
					 | 
				
			||||||
        return other is BinaryKeyBase && other.keyBytes contentEquals keyBytes
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun hashCode(): Int {
 | 
					 | 
				
			||||||
        return keyBytes.contentHashCode()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun toString(): String = keyBytes.encodeToBase64Url()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    companion object {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
open class IllegalSignatureException(text: String = "signed data is tampered or signature is corrupted") :
 | 
					 | 
				
			||||||
    IllegalStateException(text)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ExpiredSignatureException(text: String) : IllegalSignatureException(text)
 | 
					 | 
				
			||||||
@ -191,10 +191,6 @@ sealed class Container {
 | 
				
			|||||||
                            key(k)
 | 
					                            key(k)
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        is UniversalKey.Secret -> {
 | 
					 | 
				
			||||||
                            key(k.key.publicKey)
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        else -> {
 | 
					                        else -> {
 | 
				
			||||||
                            throw IllegalStateException("unknown key type to convert container: ${k::class.simpleName}")
 | 
					                            throw IllegalStateException("unknown key type to convert container: ${k::class.simpleName}")
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,14 +1,12 @@
 | 
				
			|||||||
package net.sergeych.crypto2
 | 
					package net.sergeych.crypto2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Marker interface: anything that is a key of some sort and can be identified
 | 
				
			||||||
 | 
					 * with [KeyId].
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note that to be keyring-capable it should inherit from [UniversalKey]
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
interface KeyInstance {
 | 
					interface KeyInstance {
 | 
				
			||||||
    val id: KeyId
 | 
					    val id: KeyId
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Create a new instance of the corresponding key.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
@Suppress("unused")
 | 
					 | 
				
			||||||
fun KeyInstance.toUniversalKey(): UniversalKey {
 | 
					 | 
				
			||||||
    if (this is UniversalKey) return this
 | 
					 | 
				
			||||||
    return UniversalKey.from(this)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,7 @@ package net.sergeych.crypto2
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import com.ionspin.kotlin.crypto.signature.InvalidSignatureException
 | 
					import com.ionspin.kotlin.crypto.signature.InvalidSignatureException
 | 
				
			||||||
import com.ionspin.kotlin.crypto.signature.Signature
 | 
					import com.ionspin.kotlin.crypto.signature.Signature
 | 
				
			||||||
 | 
					import kotlinx.serialization.SerialName
 | 
				
			||||||
import kotlinx.serialization.Serializable
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
import kotlinx.serialization.Transient
 | 
					import kotlinx.serialization.Transient
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -9,7 +10,8 @@ import kotlinx.serialization.Transient
 | 
				
			|||||||
 * Public key to verify signatures only
 | 
					 * Public key to verify signatures only
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@Serializable
 | 
					@Serializable
 | 
				
			||||||
class SigningPublicKey(override val keyBytes: UByteArray) : BinaryKeyBase(), VerifyingKey {
 | 
					@SerialName("sigb")
 | 
				
			||||||
 | 
					class SigningPublicKey(override val keyBytes: UByteArray) : UniversalKey(), VerifyingKey {
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Verify the signature and return true if it is correct.
 | 
					     * Verify the signature and return true if it is correct.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,7 @@ package net.sergeych.crypto2
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import com.ionspin.kotlin.crypto.signature.Signature
 | 
					import com.ionspin.kotlin.crypto.signature.Signature
 | 
				
			||||||
import kotlinx.datetime.Instant
 | 
					import kotlinx.datetime.Instant
 | 
				
			||||||
 | 
					import kotlinx.serialization.SerialName
 | 
				
			||||||
import kotlinx.serialization.Serializable
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
import kotlinx.serialization.Transient
 | 
					import kotlinx.serialization.Transient
 | 
				
			||||||
import net.sergeych.utools.now
 | 
					import net.sergeych.utools.now
 | 
				
			||||||
@ -10,11 +11,12 @@ import net.sergeych.utools.now
 | 
				
			|||||||
 * Secret key to sign only
 | 
					 * Secret key to sign only
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@Serializable
 | 
					@Serializable
 | 
				
			||||||
 | 
					@SerialName("sigs")
 | 
				
			||||||
class SigningSecretKey(
 | 
					class SigningSecretKey(
 | 
				
			||||||
        override val keyBytes: UByteArray,
 | 
					        override val keyBytes: UByteArray,
 | 
				
			||||||
        @Transient
 | 
					        @Transient
 | 
				
			||||||
        private var cachedPublicKey: SigningPublicKey?=null
 | 
					        private var cachedPublicKey: SigningPublicKey?=null
 | 
				
			||||||
    ) : BinaryKeyBase(), SigningKey {
 | 
					    ) : UniversalKey(), SigningKey {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override val verifyingKey: SigningPublicKey by lazy {
 | 
					    override val verifyingKey: SigningPublicKey by lazy {
 | 
				
			||||||
        cachedPublicKey ?:
 | 
					        cachedPublicKey ?:
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@ package net.sergeych.crypto2
 | 
				
			|||||||
import com.ionspin.kotlin.crypto.secretbox.SecretBox
 | 
					import com.ionspin.kotlin.crypto.secretbox.SecretBox
 | 
				
			||||||
import com.ionspin.kotlin.crypto.secretbox.crypto_secretbox_KEYBYTES
 | 
					import com.ionspin.kotlin.crypto.secretbox.crypto_secretbox_KEYBYTES
 | 
				
			||||||
import com.ionspin.kotlin.crypto.secretbox.crypto_secretbox_NONCEBYTES
 | 
					import com.ionspin.kotlin.crypto.secretbox.crypto_secretbox_NONCEBYTES
 | 
				
			||||||
 | 
					import kotlinx.serialization.SerialName
 | 
				
			||||||
import kotlinx.serialization.Serializable
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
import kotlinx.serialization.Transient
 | 
					import kotlinx.serialization.Transient
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -18,11 +19,14 @@ import kotlinx.serialization.Transient
 | 
				
			|||||||
 * - Authentication: Poly1305 MAC
 | 
					 * - Authentication: Poly1305 MAC
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@Serializable
 | 
					@Serializable
 | 
				
			||||||
 | 
					@SerialName("sym")
 | 
				
			||||||
class SymmetricKey(
 | 
					class SymmetricKey(
 | 
				
			||||||
    val keyBytes: UByteArray,
 | 
					    override val keyBytes: UByteArray,
 | 
				
			||||||
    @Transient
 | 
					    @Transient
 | 
				
			||||||
    val pbkdfParams: PBKD.Params?=null
 | 
					    val pbkdfParams: PBKD.Params?=null
 | 
				
			||||||
) : EncryptingKey, DecryptingKey {
 | 
					) : EncryptingKey, DecryptingKey, UniversalKey() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override val magick: KeysMagickNumber = KeysMagickNumber.defaultSymmetric
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * @suppress
 | 
					     * @suppress
 | 
				
			||||||
 | 
				
			|||||||
@ -1,116 +1,35 @@
 | 
				
			|||||||
package net.sergeych.crypto2
 | 
					package net.sergeych.crypto2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import kotlinx.serialization.SerialName
 | 
					 | 
				
			||||||
import kotlinx.serialization.Serializable
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
import kotlinx.serialization.Transient
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Serializable implementation of the _any key_ conception. Allows serializing collections
 | 
					 | 
				
			||||||
 * of different keys with arbitrary types, such as [UniversalRing].
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * To create an `UniversalKey` instance use [UniversalKey.from] or [KeyInstance]
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
@Serializable
 | 
					@Serializable
 | 
				
			||||||
sealed class UniversalKey {
 | 
					sealed class UniversalKey: KeyInstance {
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Propagate real ley instance. Base class itself can't be a key instance, but
 | 
					 | 
				
			||||||
     * has the same id. This allows requiring key instances in [UniversalRing].
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    abstract val id: KeyId
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Serializable
 | 
					    abstract val keyBytes: UByteArray
 | 
				
			||||||
    @SerialName("sym")
 | 
					    abstract val magick: KeysMagickNumber
 | 
				
			||||||
    data class Symmetric(val key: SymmetricKey) : UniversalKey(), EncryptingKey by key, DecryptingKey by key {
 | 
					 | 
				
			||||||
        @Transient
 | 
					 | 
				
			||||||
        override val id: KeyId = key.id
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        @Transient
 | 
					    override val id by lazy { KeyId(magick, keyBytes) }
 | 
				
			||||||
        override val nonceBytesLength: Int = key.nonceBytesLength
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        override fun toString() = "U.Sym:$id"
 | 
					    override fun equals(other: Any?): Boolean {
 | 
				
			||||||
 | 
					        return other is UniversalKey && other.keyBytes contentEquals keyBytes
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Serializable
 | 
					    override fun hashCode(): Int {
 | 
				
			||||||
    @SerialName("ssn")
 | 
					        return keyBytes.contentHashCode()
 | 
				
			||||||
    data class Session(val key: SafeKeyExchange.SessionKey) : UniversalKey(), EncryptingKey by key,
 | 
					 | 
				
			||||||
        DecryptingKey by key {
 | 
					 | 
				
			||||||
        @Transient
 | 
					 | 
				
			||||||
        override val id: KeyId = key.id
 | 
					 | 
				
			||||||
        @Transient
 | 
					 | 
				
			||||||
        override val nonceBytesLength: Int = key.nonceBytesLength
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        override fun toString() = "U.Ssn:$id"
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Serializable
 | 
					    override fun toString(): String = keyBytes.encodeToBase64Url()
 | 
				
			||||||
    @SerialName("sec")
 | 
					 | 
				
			||||||
    data class Secret(val key: Asymmetric.SecretKey) : UniversalKey(), DecryptingKey by key {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        @Transient
 | 
					 | 
				
			||||||
        val publicKey: Public = Public(key.publicKey)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        override val id: KeyId by lazy { key.id }
 | 
					 | 
				
			||||||
        override fun toString() = "U.Sec:$id"
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Serializable
 | 
					 | 
				
			||||||
    @SerialName("pub")
 | 
					 | 
				
			||||||
    data class Public(val key: Asymmetric.PublicKey) : UniversalKey(), EncryptingKey {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        override val id: KeyId by lazy { key.id }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        override fun encryptWithNonce(plainData: UByteArray, nonce: UByteArray, randomFill: IntRange?): UByteArray =
 | 
					 | 
				
			||||||
            key.encryptMessage(plainData, nonce, randomFill= randomFill).encoded
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        override fun encrypt(plainData: UByteArray, randomFill: IntRange?): UByteArray =
 | 
					 | 
				
			||||||
            key.encryptMessage(plainData, randomFill=randomFill).encoded
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        override val nonceBytesLength: Int
 | 
					 | 
				
			||||||
            get() = Asymmetric.nonceBytesLength
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        override fun toString() = "U.Pub:$id"
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Serializable
 | 
					 | 
				
			||||||
    @SerialName("sig")
 | 
					 | 
				
			||||||
    data class Signing(val key: SigningSecretKey) : UniversalKey(), SigningKey by key {
 | 
					 | 
				
			||||||
        override val id: KeyId by lazy { key.id }
 | 
					 | 
				
			||||||
        override fun toString() = "U.Sig:$id"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /**
 | 
					 | 
				
			||||||
         * [Verifying] key, e.g. [verifyingKey] wrapped in the [UniversalKey] variant.
 | 
					 | 
				
			||||||
         */
 | 
					 | 
				
			||||||
        val publicKey by lazy { Verifying(verifyingKey) }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Serializable
 | 
					 | 
				
			||||||
    @SerialName("ver")
 | 
					 | 
				
			||||||
    data class Verifying(val key: SigningPublicKey) : UniversalKey(), VerifyingKey by key {
 | 
					 | 
				
			||||||
        override val id: KeyId by lazy { key.id }
 | 
					 | 
				
			||||||
        override fun toString() = "U.Ver:$id"
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
        fun from(key: KeyInstance): UniversalKey =
 | 
					        fun newSecretKey() = Asymmetric.newSecretKey()
 | 
				
			||||||
            when (key) {
 | 
					        fun newSigningKey() = SigningSecretKey.new()
 | 
				
			||||||
                is UniversalKey -> key
 | 
					 | 
				
			||||||
                is Asymmetric.SecretKey -> Secret(key)
 | 
					 | 
				
			||||||
                is Asymmetric.PublicKey -> Public(key)
 | 
					 | 
				
			||||||
                is SymmetricKey -> Symmetric(key)
 | 
					 | 
				
			||||||
                is SafeKeyExchange.SessionKey -> Session(key)
 | 
					 | 
				
			||||||
                else -> throw UnsupportedOperationException("can't create universal key from ${key::class.simpleName}")
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        fun newSecretKey(): Secret =
 | 
					 | 
				
			||||||
            Secret(Asymmetric.newSecretKey())
 | 
					 | 
				
			||||||
        fun newSigningKey(): Signing =
 | 
					 | 
				
			||||||
            Signing(SigningSecretKey.new())
 | 
					 | 
				
			||||||
        @Suppress("unused")
 | 
					        @Suppress("unused")
 | 
				
			||||||
        fun newSymmetricKey(): Symmetric =
 | 
					        fun newSymmetricKey() = SymmetricKey.new()
 | 
				
			||||||
            Symmetric(SymmetricKey.new())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					open class IllegalSignatureException(text: String = "signed data is tampered or signature is corrupted") :
 | 
				
			||||||
 | 
					    IllegalStateException(text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ExpiredSignatureException(text: String) : IllegalSignatureException(text)
 | 
				
			||||||
@ -17,7 +17,7 @@ import kotlinx.serialization.Serializable
 | 
				
			|||||||
class UniversalRing(
 | 
					class UniversalRing(
 | 
				
			||||||
    val keyWithTags: Map<UniversalKey, Set<String>>,
 | 
					    val keyWithTags: Map<UniversalKey, Set<String>>,
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    constructor(vararg keys: UniversalKey) : this(keys.associateWith { setOf() })
 | 
					    constructor(vararg keys: UniversalKey) : this(keys.associate { it to setOf() })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(vararg keyTags: Pair<UniversalKey, String>)
 | 
					    constructor(vararg keyTags: Pair<UniversalKey, String>)
 | 
				
			||||||
            : this(keyTags.associate { it.first to setOf(it.second) })
 | 
					            : this(keyTags.associate { it.first to setOf(it.second) })
 | 
				
			||||||
@ -37,10 +37,12 @@ class UniversalRing(
 | 
				
			|||||||
    val allKeys: Set<UniversalKey> by lazy { keyWithTags.keys }
 | 
					    val allKeys: Set<UniversalKey> by lazy { keyWithTags.keys }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Find a key of the specified type that matches the id. __Important__ it is not possible to
 | 
					     * Find a key of the specified type that matches the id. In general, you require key implementations like
 | 
				
			||||||
     * require [UniversalKey] as [T], it is not a [KeyInstance], while its descendants are, [UniversalKey.Secret], etc.
 | 
					     * [Asymmetric.SecretKey], [Asymmetric.PublicKey], [SigningPublicKey], [SigningSecretKey] and [SymmetricKey],
 | 
				
			||||||
     * You can freely use [UniversalKey] subtypes or general key interfaces, e.g.
 | 
					     * or just key interfaces: [EncryptingKey], [DecryptingKey], [SigningKey] and [VerifyingKey].
 | 
				
			||||||
     * [EncryptingKey], [DecryptingKey], [SigningKey] and [VerifyingKey].
 | 
					     *
 | 
				
			||||||
 | 
					     * Note that key interfaces are not serializable as for now, you should try to cast to a serializable
 | 
				
			||||||
 | 
					     * base.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * Please avoid selecting parameters that make possible to pick more than one key, it will cause an exception.
 | 
					     * Please avoid selecting parameters that make possible to pick more than one key, it will cause an exception.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
@ -227,15 +229,15 @@ class UniversalRing(
 | 
				
			|||||||
         * Convert any keys to [UniversalKey] and form a ring with it.
 | 
					         * Convert any keys to [UniversalKey] and form a ring with it.
 | 
				
			||||||
         * @throws UnsupportedOperationException if [UniversalKey] can't build an instance of the specified class.
 | 
					         * @throws UnsupportedOperationException if [UniversalKey] can't build an instance of the specified class.
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
        fun from(vararg keys: KeyInstance): UniversalRing =
 | 
					        fun from(vararg keys: DecryptingKey): UniversalRing =
 | 
				
			||||||
            UniversalRing(keys.associate { UniversalKey.from(it) to setOf() } )
 | 
					            UniversalRing(keys.associate { it as UniversalKey to setOf() } )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /**
 | 
					        /**
 | 
				
			||||||
         * Convert any keys to [UniversalKey] and form a ring with it.
 | 
					         * Convert any keys to [UniversalKey] and form a ring with it.
 | 
				
			||||||
         * @throws UnsupportedOperationException if [UniversalKey] can't build an instance of the specified class.
 | 
					         * @throws UnsupportedOperationException if [UniversalKey] can't build an instance of the specified class.
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
        fun from(vararg keyTags: Pair<KeyInstance,String>): UniversalRing =
 | 
					        fun from(vararg keyTags: Pair<UniversalKey,String>): UniversalRing =
 | 
				
			||||||
            UniversalRing(keyTags.associate { UniversalKey.from(it.first) to setOf(it.second) } )
 | 
					            UniversalRing(keyTags.associate {it.first to setOf(it.second) } )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										10
									
								
								src/commonMain/kotlin/net/sergeych/tools/pack_tools.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/commonMain/kotlin/net/sergeych/tools/pack_tools.kt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					package net.sergeych.tools
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import net.sergeych.bipack.BipackDecoder
 | 
				
			||||||
 | 
					import net.sergeych.bipack.BipackEncoder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified T>bipack(value: T): UByteArray = BipackEncoder.encode(value).toUByteArray()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified T>biunpack(value: UByteArray): T = BipackDecoder.decode(value.toByteArray())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -4,6 +4,8 @@ import kotlinx.coroutines.test.runTest
 | 
				
			|||||||
import kotlinx.serialization.encodeToString
 | 
					import kotlinx.serialization.encodeToString
 | 
				
			||||||
import kotlinx.serialization.json.Json
 | 
					import kotlinx.serialization.json.Json
 | 
				
			||||||
import net.sergeych.crypto2.*
 | 
					import net.sergeych.crypto2.*
 | 
				
			||||||
 | 
					import net.sergeych.tools.bipack
 | 
				
			||||||
 | 
					import net.sergeych.tools.biunpack
 | 
				
			||||||
import net.sergeych.utools.now
 | 
					import net.sergeych.utools.now
 | 
				
			||||||
import net.sergeych.utools.pack
 | 
					import net.sergeych.utools.pack
 | 
				
			||||||
import net.sergeych.utools.unpack
 | 
					import net.sergeych.utools.unpack
 | 
				
			||||||
@ -187,9 +189,9 @@ class KeysTest {
 | 
				
			|||||||
        assertEquals(sy1, deepCopy(sy1), "symmetric key should be equal to the restored copy")
 | 
					        assertEquals(sy1, deepCopy(sy1), "symmetric key should be equal to the restored copy")
 | 
				
			||||||
        assertEquals(sy1.hashCode(), deepCopy(sy1).hashCode(), "hashcode of the restored symmetric key is wrong")
 | 
					        assertEquals(sy1.hashCode(), deepCopy(sy1).hashCode(), "hashcode of the restored symmetric key is wrong")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val usy1 = UniversalKey.from(sy1)
 | 
					        val usy1 = sy1 as UniversalKey
 | 
				
			||||||
        val usy2 = UniversalKey.from(sy2)
 | 
					        val usy2 = sy2 as UniversalKey
 | 
				
			||||||
        val usy3 = UniversalKey.from(sy3)
 | 
					        val usy3 = sy3 as UniversalKey
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assertEquals(usy1, usy2)
 | 
					        assertEquals(usy1, usy2)
 | 
				
			||||||
        assertEquals(usy2, usy1)
 | 
					        assertEquals(usy2, usy1)
 | 
				
			||||||
@ -203,10 +205,10 @@ class KeysTest {
 | 
				
			|||||||
        assertEquals(sk2, sk1)
 | 
					        assertEquals(sk2, sk1)
 | 
				
			||||||
        assertFalse { sk1 == sk3 }
 | 
					        assertFalse { sk1 == sk3 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var usk1 = UniversalKey.from(sk1)
 | 
					        var usk1 = sk1 as UniversalKey
 | 
				
			||||||
        var usk2 = UniversalKey.from(sk2)
 | 
					        var usk2 = sk2 as UniversalKey
 | 
				
			||||||
        var usk3 = UniversalKey.from(sk3)
 | 
					        var usk3 = sk3 as UniversalKey
 | 
				
			||||||
        val usk4 = UniversalKey.from(sy3)
 | 
					        val usk4 = sy3 as UniversalKey
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assertEquals(usk1, usk2)
 | 
					        assertEquals(usk1, usk2)
 | 
				
			||||||
        assertEquals(usk2, usk1)
 | 
					        assertEquals(usk2, usk1)
 | 
				
			||||||
@ -223,7 +225,7 @@ class KeysTest {
 | 
				
			|||||||
        usk2 = deepCopy(usk2)
 | 
					        usk2 = deepCopy(usk2)
 | 
				
			||||||
        usk3 = deepCopy(usk3)
 | 
					        usk3 = deepCopy(usk3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assertEquals(usk1.hashCode(),usk2.hashCode())
 | 
					        assertEquals(usk1.hashCode(), usk2.hashCode())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assertEquals(usk1, usk2)
 | 
					        assertEquals(usk1, usk2)
 | 
				
			||||||
        assertEquals(usk2, usk1)
 | 
					        assertEquals(usk2, usk1)
 | 
				
			||||||
@ -239,4 +241,13 @@ class KeysTest {
 | 
				
			|||||||
        // usk1 and usk2 are equal so set with only one of should be the same
 | 
					        // usk1 and usk2 are equal so set with only one of should be the same
 | 
				
			||||||
        assertEquals(a, setOf(usk1, usk3, usk4))
 | 
					        assertEquals(a, setOf(usk1, usk3, usk4))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    fun testKiSerialization() = runTest {
 | 
				
			||||||
 | 
					        initCrypto()
 | 
				
			||||||
 | 
					        val k: UniversalKey = SymmetricKey.new()
 | 
				
			||||||
 | 
					        val d = bipack(k)
 | 
				
			||||||
 | 
					        val k1: UniversalKey = biunpack<UniversalKey>(d) as SymmetricKey
 | 
				
			||||||
 | 
					        assertEquals(k, k1)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -20,14 +20,14 @@ class RingTest {
 | 
				
			|||||||
        val e2: Asymmetric.SecretKey = BipackDecoder.decode(BipackEncoder.encode(e1))
 | 
					        val e2: Asymmetric.SecretKey = BipackDecoder.decode(BipackEncoder.encode(e1))
 | 
				
			||||||
        assertEquals(e1, e2)
 | 
					        assertEquals(e1, e2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val k1 = UniversalKey.from(SymmetricKey("1234567890Hello,dolly.here-we-go".encodeToUByteArray()))
 | 
					        val k1 = SymmetricKey("1234567890Hello,dolly.here-we-go".encodeToUByteArray()) as UniversalKey
 | 
				
			||||||
        val k11 = UniversalKey.from(SymmetricKey("1234567890Hello,dolly.here-we-go".encodeToUByteArray()))
 | 
					        val k11 = SymmetricKey("1234567890Hello,dolly.here-we-go".encodeToUByteArray()) as UniversalKey
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assertEquals(k1, k11)
 | 
					        assertEquals(k1, k11)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val k2 = UniversalKey.from(Asymmetric.newSecretKey())
 | 
					        val k2 = Asymmetric.newSecretKey()
 | 
				
			||||||
        val k3 = UniversalKey.from(Asymmetric.newSecretKey())
 | 
					        val k3 = Asymmetric.newSecretKey()
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
        val r = UniversalRing(k1, k2)
 | 
					        val r = UniversalRing(k1, k2)
 | 
				
			||||||
//        val r = UniversalRing(k1)
 | 
					//        val r = UniversalRing(k1)
 | 
				
			||||||
@ -40,7 +40,7 @@ class RingTest {
 | 
				
			|||||||
        val encoded = BipackEncoder.encode(r)
 | 
					        val encoded = BipackEncoder.encode(r)
 | 
				
			||||||
        println(encoded.toDump())
 | 
					        println(encoded.toDump())
 | 
				
			||||||
        println(encoded.size)
 | 
					        println(encoded.size)
 | 
				
			||||||
        assertTrue { encoded.size < 80 }
 | 
					        assertTrue { encoded.size < 82 }
 | 
				
			||||||
        val r2: UniversalRing = BipackDecoder.decode(encoded)
 | 
					        val r2: UniversalRing = BipackDecoder.decode(encoded)
 | 
				
			||||||
        assertTrue { k2 in r2 }
 | 
					        assertTrue { k2 in r2 }
 | 
				
			||||||
        assertTrue { k1 in r2 }
 | 
					        assertTrue { k1 in r2 }
 | 
				
			||||||
@ -69,16 +69,16 @@ class RingTest {
 | 
				
			|||||||
        val r1 = deepCopy(r)
 | 
					        val r1 = deepCopy(r)
 | 
				
			||||||
        println(r1.findKey<EncryptingKey>(sk.id))
 | 
					        println(r1.findKey<EncryptingKey>(sk.id))
 | 
				
			||||||
        println(sk)
 | 
					        println(sk)
 | 
				
			||||||
        assertTrue { sk.publicKey.toUniversalKey() == r1.findKey<EncryptingKey>(sk.id) }
 | 
					        assertTrue { sk.publicKey as UniversalKey == r1.findKey<EncryptingKey>(sk.id) }
 | 
				
			||||||
        assertTrue { sk.publicKey.toUniversalKey() == r1.keyByTag<EncryptingKey>("foo") }
 | 
					        assertTrue { sk.publicKey as UniversalKey == r1.keyByTag<EncryptingKey>("foo") }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Test
 | 
					    @Test
 | 
				
			||||||
    fun testTags() = runTest {
 | 
					    fun testTags() = runTest {
 | 
				
			||||||
        initCrypto()
 | 
					        initCrypto()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val k1 = UniversalKey.from(SymmetricKey("1234567890Hello,dolly.here-we-go".encodeToUByteArray()))
 | 
					        val k1 = SymmetricKey("1234567890Hello,dolly.here-we-go".encodeToUByteArray()) as UniversalKey
 | 
				
			||||||
        val k2 = UniversalKey.from(Asymmetric.newSecretKey())
 | 
					        val k2 = Asymmetric.newSecretKey() as UniversalKey
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val r1 = UniversalRing(k1, k2)
 | 
					        val r1 = UniversalRing(k1, k2)
 | 
				
			||||||
        var r2 = UniversalRing(deepCopy(k1), deepCopy(k2))
 | 
					        var r2 = UniversalRing(deepCopy(k1), deepCopy(k2))
 | 
				
			||||||
@ -114,7 +114,7 @@ class RingTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        val data = "Mendeleev' table".encodeToUByteArray()
 | 
					        val data = "Mendeleev' table".encodeToUByteArray()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var r = UniversalRing(sk2, sk3, sk1.publicKey, sk3.publicKey, sik3.publicKey, sik1.publicKey)
 | 
					        var r = UniversalRing(sk2, sk3, sk1.publicKey, sk3.publicKey, sik3.verifyingKey, sik1.verifyingKey)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        r = r.addTags(sik1, "SECRET_SIGN")
 | 
					        r = r.addTags(sik1, "SECRET_SIGN")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -122,11 +122,11 @@ class RingTest {
 | 
				
			|||||||
        assertContentEquals(data, box.decryptWith(r))
 | 
					        assertContentEquals(data, box.decryptWith(r))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assertEquals(sk3.publicKey, r.findKey<EncryptingKey>(sk3.id))
 | 
					        assertEquals(sk3.publicKey, r.findKey<EncryptingKey>(sk3.id))
 | 
				
			||||||
        assertTrue { sik3.publicKey in r }
 | 
					        assertTrue { sik3.verifyingKey in r }
 | 
				
			||||||
        assertTrue { sik1 in r }
 | 
					        assertTrue { sik1 in r }
 | 
				
			||||||
        assertEquals(sik1, r.keyByTag<UniversalKey>("SECRET_SIGN"))
 | 
					        assertEquals(sik1, r.keyByTag<UniversalKey>("SECRET_SIGN"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assertEquals(sik1, r.findKey<SigningKey>(sik1.publicKey.id))
 | 
					        assertEquals(sik1, r.findKey<SigningKey>(sik1.verifyingKey.id))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Test
 | 
					    @Test
 | 
				
			||||||
@ -154,17 +154,17 @@ class RingTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        var r1 = ra + rb + rc + rd
 | 
					        var r1 = ra + rb + rc + rd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assertEquals(a, r1.findKey<UniversalKey.Secret>(a.id))
 | 
					        assertEquals(a, r1.findKey<Asymmetric.SecretKey>(a.id))
 | 
				
			||||||
        assertEquals(a, r1.keyByTag<UniversalKey>("foo_a"))
 | 
					        assertEquals(a, r1.keyByTag<UniversalKey>("foo_a"))
 | 
				
			||||||
        assertEquals(b, r1.findKey<SigningKey>(b.id))
 | 
					        assertEquals(b, r1.findKey<SigningKey>(b.id))
 | 
				
			||||||
        assertEquals(c, r1.keysById(c.key.id).first())
 | 
					        assertEquals(c, r1.keysById(c.id).first())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        r1 = UniversalRing.join(listOf(ra, rb, rc, rd))
 | 
					        r1 = UniversalRing.join(listOf(ra, rb, rc, rd))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assertEquals(a, r1.findKey<UniversalKey.Secret>(a.id))
 | 
					        assertEquals(a, r1.findKey<Asymmetric.SecretKey>(a.id))
 | 
				
			||||||
        assertEquals(a, r1.keyByTag<UniversalKey>("foo_a"))
 | 
					        assertEquals(a, r1.keyByTag<UniversalKey>("foo_a"))
 | 
				
			||||||
        assertEquals(b, r1.findKey<SigningKey>(b.id))
 | 
					        assertEquals(b, r1.findKey<SigningKey>(b.id))
 | 
				
			||||||
        assertEquals(c, r1.keysById(c.key.id).first())
 | 
					        assertEquals(c, r1.keysById(c.id).first())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user