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
|
||||
.kotlin
|
||||
.idea
|
||||
.gigaide
|
||||
/kotlin-js-store/yarn.lock
|
||||
|
@ -8,7 +8,7 @@ plugins {
|
||||
}
|
||||
|
||||
group = "net.sergeych"
|
||||
version = "0.5.9-SNAPSHOT"
|
||||
version = "0.6.1-SNAPSHOT"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
@ -20,6 +20,8 @@ import net.sergeych.crypto2.Container.Companion.createWith
|
||||
* - [addRecipients] and various [plus] operators to add recipients
|
||||
* - [updateData] to change decrypted content for the same recipient keys
|
||||
*
|
||||
* Note that container _is serialized encrypted_.
|
||||
*
|
||||
* Some rules:
|
||||
*
|
||||
* 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
|
||||
|
||||
/**
|
||||
* Binary encoded version. It is desirable to include [Container] as an object, though,
|
||||
* especially when using custom serialization (Json, Boss, etc), it is serializable.
|
||||
* 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. 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
|
||||
* [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? =
|
||||
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? =
|
||||
decode(cipherData).decryptWith(*keys)
|
||||
|
||||
|
@ -6,6 +6,11 @@ enum class KeysmagicNumber(val label: String) {
|
||||
defaultSymmetric( "sym"),
|
||||
defaultSession( "ssn"),
|
||||
defaultVerifying( "ver"),
|
||||
|
||||
defaultSigningSecret( "sig"),
|
||||
|
||||
defaultUniversalPublic( "pub+"),
|
||||
defaultUniversalPrivate( "prv+"),
|
||||
;
|
||||
|
||||
}
|
@ -23,6 +23,8 @@ class SigningSecretKey(
|
||||
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 seal(message: UByteArray, expiresAt: Instant?): Seal =
|
||||
|
@ -8,7 +8,6 @@ sealed class UniversalKey: KeyInstance {
|
||||
|
||||
abstract val keyBytes: UByteArray
|
||||
|
||||
|
||||
@Transient
|
||||
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(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