fix #1 UniversalPrivateKey & UniversalPublicKey
This commit is contained in:
		
							parent
							
								
									194fe22afa
								
							
						
					
					
						commit
						640ceb448e
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -41,4 +41,5 @@ out/
 | 
				
			|||||||
# Other
 | 
					# Other
 | 
				
			||||||
.kotlin
 | 
					.kotlin
 | 
				
			||||||
.idea
 | 
					.idea
 | 
				
			||||||
 | 
					.gigaide
 | 
				
			||||||
/kotlin-js-store/yarn.lock
 | 
					/kotlin-js-store/yarn.lock
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,7 @@ plugins {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
group = "net.sergeych"
 | 
					group = "net.sergeych"
 | 
				
			||||||
version = "0.5.9-SNAPSHOT"
 | 
					version = "0.6.1-SNAPSHOT"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
repositories {
 | 
					repositories {
 | 
				
			||||||
    mavenCentral()
 | 
					    mavenCentral()
 | 
				
			||||||
 | 
				
			|||||||
@ -20,6 +20,8 @@ import net.sergeych.crypto2.Container.Companion.createWith
 | 
				
			|||||||
 * - [addRecipients] and various [plus] operators to add recipients
 | 
					 * - [addRecipients] and various [plus] operators to add recipients
 | 
				
			||||||
 * - [updateData] to change decrypted content for the same recipient keys
 | 
					 * - [updateData] to change decrypted content for the same recipient keys
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 | 
					 * Note that container _is serialized encrypted_.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 * Some rules:
 | 
					 * Some rules:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * When adding public key recipient, it is faster to use your known [SecretKey], but you
 | 
					 * When adding public key recipient, it is faster to use your known [SecretKey], but you
 | 
				
			||||||
@ -126,8 +128,9 @@ sealed class Container {
 | 
				
			|||||||
    abstract fun updateData(newPlainData: UByteArray, randomFill: IntRange? = null): Container
 | 
					    abstract fun updateData(newPlainData: UByteArray, randomFill: IntRange? = null): Container
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Binary encoded version. It is desirable to include [Container] as an object, though,
 | 
					     * Binary encoded _encrypted_ version. It is desirable to include [Container] as an object, though,
 | 
				
			||||||
     * especially when using custom serialization (Json, Boss, etc), it is serializable.
 | 
					     * especially when using custom serialization (Json, Boss, etc.), it is serializable. Note that
 | 
				
			||||||
 | 
					     * serialized data is always encrypted.
 | 
				
			||||||
     * Still, if you need it in binary form, this is a shortcut. You can use [decode] or call
 | 
					     * 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.
 | 
					     * [BipackDecoder.decode] to deserialize the binary form.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
@ -474,6 +477,12 @@ sealed class Container {
 | 
				
			|||||||
        inline fun <reified T> decrypt(cipherData: UByteArray, vararg keys: DecryptingKey): T? =
 | 
					        inline fun <reified T> decrypt(cipherData: UByteArray, vararg keys: DecryptingKey): T? =
 | 
				
			||||||
            decryptAsUBytes(cipherData, *keys)?.let { BipackDecoder.decode<T>(it.asByteArray()) }
 | 
					            decryptAsUBytes(cipherData, *keys)?.let { BipackDecoder.decode<T>(it.asByteArray()) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        inline fun <reified T> decrypt(cipherData: UByteArray, ring: UniversalRing): T? =
 | 
				
			||||||
 | 
					            decode(cipherData)
 | 
				
			||||||
 | 
					                .decryptWith(ring)?.let {
 | 
				
			||||||
 | 
					                    BipackDecoder.decode<T>(it.asByteArray())
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fun decryptAsUBytes(cipherData: UByteArray, vararg keys: DecryptingKey): UByteArray? =
 | 
					        fun decryptAsUBytes(cipherData: UByteArray, vararg keys: DecryptingKey): UByteArray? =
 | 
				
			||||||
            decode(cipherData).decryptWith(*keys)
 | 
					            decode(cipherData).decryptWith(*keys)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,11 @@ enum class KeysmagicNumber(val label: String) {
 | 
				
			|||||||
    defaultSymmetric( "sym"),
 | 
					    defaultSymmetric( "sym"),
 | 
				
			||||||
    defaultSession( "ssn"),
 | 
					    defaultSession( "ssn"),
 | 
				
			||||||
    defaultVerifying( "ver"),
 | 
					    defaultVerifying( "ver"),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    defaultSigningSecret( "sig"),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    defaultUniversalPublic( "pub+"),
 | 
				
			||||||
 | 
					    defaultUniversalPrivate( "prv+"),
 | 
				
			||||||
    ;
 | 
					    ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -23,6 +23,8 @@ class SigningSecretKey(
 | 
				
			|||||||
            VerifyingPublicKey(Signature.ed25519SkToPk(keyBytes)).also { cachedPublicKey = it }
 | 
					            VerifyingPublicKey(Signature.ed25519SkToPk(keyBytes)).also { cachedPublicKey = it }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override val magic: KeysmagicNumber = KeysmagicNumber.defaultSigningSecret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun sign(message: UByteArray): UByteArray = Signature.detached(message, keyBytes)
 | 
					    override fun sign(message: UByteArray): UByteArray = Signature.detached(message, keyBytes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun seal(message: UByteArray, expiresAt: Instant?): Seal =
 | 
					    override fun seal(message: UByteArray, expiresAt: Instant?): Seal =
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,6 @@ sealed class UniversalKey: KeyInstance {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    abstract val keyBytes: UByteArray
 | 
					    abstract val keyBytes: UByteArray
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Transient
 | 
					    @Transient
 | 
				
			||||||
    open val magic: KeysmagicNumber = KeysmagicNumber.Unknown
 | 
					    open val magic: KeysmagicNumber = KeysmagicNumber.Unknown
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					package net.sergeych.crypto2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.SerialName
 | 
				
			||||||
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					import kotlinx.serialization.Transient
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Combination of private/secret keys suitable for both decryption and signing.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * It contains two cryptographically independent keys to raise security to a maximum.
 | 
				
			||||||
 | 
					 * Any converted keys poses a threat while technically possible so we avoid it.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Serializable
 | 
				
			||||||
 | 
					@SerialName("uprv")
 | 
				
			||||||
 | 
					class UniversalPrivateKey(
 | 
				
			||||||
 | 
					    val signingKey: SigningSecretKey,
 | 
				
			||||||
 | 
					    val decryptingKey: SecretKey
 | 
				
			||||||
 | 
					) : UniversalKey(), DecryptingKey by decryptingKey, SigningKey by signingKey {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override val keyBytes by lazy { signingKey.keyBytes + decryptingKey.keyBytes }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Transient
 | 
				
			||||||
 | 
					    override val magic = KeysmagicNumber.defaultUniversalPrivate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Important! Private key combines signing and decrypting keys, but uses
 | 
				
			||||||
 | 
					     * it of the decrypting one to be used in keyring.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Transient
 | 
				
			||||||
 | 
					    override val id: KeyId = decryptingKey.id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Corresponding public key able to verify amd encrypt data created by this
 | 
				
			||||||
 | 
					     * private key.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    val publicKey by lazy {
 | 
				
			||||||
 | 
					        UniversalPublicKey(signingKey.verifyingKey, decryptingKey.publicKey)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    companion object {
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * Generate 2 new random keys (4 key pairs under the hood) to securely signd and
 | 
				
			||||||
 | 
					         * decrypt data.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        fun new() = UniversalPrivateKey(SigningSecretKey.new(), SecretKey.new())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					package net.sergeych.crypto2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.SerialName
 | 
				
			||||||
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					import kotlinx.serialization.Transient
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Combination of public keys suitable for both encryption and verification. A counterpart
 | 
				
			||||||
 | 
					 * of the [UniversalPrivateKey], available also as [UniversalPrivateKey.publicKey].
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * When using [UniversalRing] and [Container], data encrypted with instances og this class
 | 
				
			||||||
 | 
					 * can be decrypted with rings containing the corresponding [UniversalPrivateKey].
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Serializable
 | 
				
			||||||
 | 
					@SerialName("upub")
 | 
				
			||||||
 | 
					class UniversalPublicKey(
 | 
				
			||||||
 | 
					    val verifyingKey: VerifyingPublicKey,
 | 
				
			||||||
 | 
					    val encryptingKey: PublicKey
 | 
				
			||||||
 | 
					): UniversalKey(), VerifyingKey by verifyingKey, EncryptingKey by encryptingKey{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override val keyBytes by lazy { verifyingKey.keyBytes + encryptingKey.keyBytes }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Transient
 | 
				
			||||||
 | 
					    override val magic = KeysmagicNumber.defaultUniversalPublic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Important! Private key combines signing and decrypting keys, but uses
 | 
				
			||||||
 | 
					     * it of the decrypting one to be used in keyring.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Transient
 | 
				
			||||||
 | 
					    override val id: KeyId = encryptingKey.id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -360,4 +360,34 @@ class KeysTest {
 | 
				
			|||||||
        assertTrue { mk.check(k4.verifyingKey) }
 | 
					        assertTrue { mk.check(k4.verifyingKey) }
 | 
				
			||||||
        assertTrue { mk.check(k5.verifyingKey) }
 | 
					        assertTrue { mk.check(k5.verifyingKey) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    fun testCombinedKeys() = runTest {
 | 
				
			||||||
 | 
					        initCrypto()
 | 
				
			||||||
 | 
					        val k1 = UniversalPrivateKey.new()
 | 
				
			||||||
 | 
					        val k2 = UniversalPrivateKey.new()
 | 
				
			||||||
 | 
					        val k3: UniversalPrivateKey = unpack(pack(k1))
 | 
				
			||||||
 | 
					        assertEquals(k1, k3)
 | 
				
			||||||
 | 
					        assertEquals(k1.publicKey, k3.publicKey)
 | 
				
			||||||
 | 
					        assertEquals(k1.signingKey, k3.signingKey)
 | 
				
			||||||
 | 
					        assertEquals(k1.verifyingKey, k3.verifyingKey)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val k4: UniversalPublicKey = unpack(pack(k1.publicKey))
 | 
				
			||||||
 | 
					        assertEquals(k1.publicKey, k4)
 | 
				
			||||||
 | 
					        assertEquals(k1.publicKey.encryptingKey, k4.encryptingKey)
 | 
				
			||||||
 | 
					        assertEquals(k1.publicKey.verifyingKey, k4.verifyingKey)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val data =
 | 
				
			||||||
 | 
					            """We hold these truths to be self-evident, that all men are created equal, 
 | 
				
			||||||
 | 
					                |that they are endowed by their Creator with certain unalienable Rights, 
 | 
				
			||||||
 | 
					                |that among these are Life, Liberty and the pursuit of Happiness."""
 | 
				
			||||||
 | 
					                .trimMargin()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val kr1 = UniversalRing.from(k1)
 | 
				
			||||||
 | 
					        val kr2: UniversalRing = UniversalRing.from(k2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val bytes = Container.encrypt(data, k2.publicKey)
 | 
				
			||||||
 | 
					        assertNull(Container.decrypt<String>(bytes, kr1))
 | 
				
			||||||
 | 
					        assertEquals(data, Container.decrypt<String>(bytes, kr2))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user