fixed SafeKeyEXchange.SessionKey serialization issue
This commit is contained in:
parent
84a3e82216
commit
66254f8fa6
1
.idea/misc.xml
generated
1
.idea/misc.xml
generated
@ -1,3 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="FrameworkDetectionExcludesConfiguration">
|
||||
|
||||
@ -13,14 +13,14 @@ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
kotlin("multiplatform") version "2.2.21"
|
||||
id("org.jetbrains.kotlin.plugin.serialization") version "2.2.21"
|
||||
kotlin("multiplatform") version "2.4.0"
|
||||
id("org.jetbrains.kotlin.plugin.serialization") version "2.4.0"
|
||||
id("org.jetbrains.dokka") version "1.9.20"
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
group = "net.sergeych"
|
||||
version = "0.9.3"
|
||||
version = "0.9.4-SNAPSHOT"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
||||
@ -155,15 +155,9 @@ sealed class Container {
|
||||
abstract val decryptedWithKeyId: KeyId?
|
||||
|
||||
/**
|
||||
* If the container _is decrypted by the [EncryptingPublicKey]_, e.g., using secret key encryption,
|
||||
* contains the [EncryptingPublicKey] that corresponds the [DecryptingSecretKey] used while encrypting, this
|
||||
* authenticating the sender party cryptographically. This key could be used to encrypt
|
||||
* the response to be visible to the sender only; the sender, providing it kept his secret key,
|
||||
* could decrypt it.
|
||||
* When the container is decrypted, the key that unlocked it, otherwise null.
|
||||
*/
|
||||
@Transient
|
||||
var authorisedByKey: EncryptingPublicKey? = null
|
||||
protected set
|
||||
abstract val decryptedWithKey: UniversalKey?
|
||||
|
||||
/**
|
||||
* List of [KeyId] of the keys that unlocked the container, in the same order used for encryption..
|
||||
@ -185,7 +179,8 @@ sealed class Container {
|
||||
) : Container() {
|
||||
|
||||
@Transient
|
||||
private var decryptedWithKey: DecryptingKey? = null
|
||||
override var decryptedWithKey: UniversalKey? = null
|
||||
private set
|
||||
|
||||
override val decryptedWithKeyId: KeyId?
|
||||
get() = decryptedWithKey?.id
|
||||
@ -202,10 +197,7 @@ sealed class Container {
|
||||
if (k.id == keyId) {
|
||||
kotlin.runCatching { k.decrypt(encryptedMessage) }.getOrNull()?.let {
|
||||
decryptedData = it
|
||||
decryptedWithKey = k
|
||||
if(k is DecryptingSecretKey) {
|
||||
authorisedByKey = Asymmetric.Message.decode(encryptedMessage).senderPublicKey
|
||||
}
|
||||
decryptedWithKey = k as UniversalKey
|
||||
return it
|
||||
}
|
||||
}
|
||||
@ -284,9 +276,12 @@ sealed class Container {
|
||||
}
|
||||
|
||||
@Transient
|
||||
override var decryptedWithKeyId: KeyId? = null
|
||||
override var decryptedWithKey: UniversalKey? = null
|
||||
private set
|
||||
|
||||
override val decryptedWithKeyId: KeyId?
|
||||
get() = decryptedWithKey?.id
|
||||
|
||||
override val keyIds: List<KeyId> = encryptedKeys.map { it.tag }
|
||||
|
||||
override fun decryptWith(keyRing: UniversalRing): UByteArray? {
|
||||
@ -302,11 +297,8 @@ sealed class Container {
|
||||
}.getOrNull()?.let { k ->
|
||||
if (kotlin.runCatching { decryptedData = k.decrypt(encryptedMessage) }.isFailure)
|
||||
throw InvalidContainerException()
|
||||
decryptedWithKeyId = key.id
|
||||
decryptedWithKey = key as UniversalKey
|
||||
mainKey = k
|
||||
if(key is DecryptingSecretKey) {
|
||||
authorisedByKey = Asymmetric.Message.decode(encryptedKey.cipherData).senderPublicKey
|
||||
}
|
||||
}
|
||||
if (decryptedData != null) return decryptedData
|
||||
}
|
||||
|
||||
@ -15,6 +15,7 @@ import com.ionspin.kotlin.crypto.keyexchange.KeyExchangeKeyPair
|
||||
import com.ionspin.kotlin.crypto.keyexchange.crypto_kx_PUBLICKEYBYTES
|
||||
import com.ionspin.kotlin.crypto.keyexchange.crypto_kx_SECRETKEYBYTES
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.SerializationException
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
@ -81,7 +82,7 @@ class SafeKeyExchange private constructor(
|
||||
* The session key. It uses a pair of keys to encrypt and decrypt messages to maintain high
|
||||
* security level and allow using counters as nonce with no extra precautions.
|
||||
*/
|
||||
@Serializable
|
||||
@Serializable(with = SafeKeyExchange.SessionKeySerializer::class)
|
||||
class SessionKey(
|
||||
val sendingKey: EncryptingKey,
|
||||
val receivingKey: DecryptingKey,
|
||||
@ -128,6 +129,36 @@ class SafeKeyExchange private constructor(
|
||||
|
||||
}
|
||||
|
||||
@Serializable
|
||||
private class PackedSessionKey(
|
||||
val sendingKey: SymmetricKey,
|
||||
val receivingKey: SymmetricKey,
|
||||
val isClient: Boolean,
|
||||
)
|
||||
|
||||
object SessionKeySerializer : KSerializer<SessionKey> {
|
||||
private val packedSerializer = PackedSessionKey.serializer()
|
||||
|
||||
override val descriptor: SerialDescriptor = packedSerializer.descriptor
|
||||
|
||||
override fun serialize(encoder: Encoder, value: SessionKey) {
|
||||
val sendingKey = value.sendingKey as? SymmetricKey
|
||||
?: throw SerializationException("SessionKey.sendingKey must be SymmetricKey")
|
||||
val receivingKey = value.receivingKey as? SymmetricKey
|
||||
?: throw SerializationException("SessionKey.receivingKey must be SymmetricKey")
|
||||
|
||||
encoder.encodeSerializableValue(
|
||||
packedSerializer,
|
||||
PackedSessionKey(sendingKey, receivingKey, value.isClient)
|
||||
)
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): SessionKey {
|
||||
val packed = decoder.decodeSerializableValue(packedSerializer)
|
||||
return SessionKey(packed.sendingKey, packed.receivingKey, packed.isClient)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The public key; it should be transmitted to the other party, this is serializable.
|
||||
* Do not use it except to get [SessionKey] with [clientSessionKey] or [serverSessionKey]. Storing and reusing
|
||||
|
||||
@ -34,6 +34,8 @@ class ContainerTest {
|
||||
assertNotNull(d)
|
||||
assertContentEquals(data, d)
|
||||
assertTrue { c1.isDecrypted }
|
||||
assertEquals(syk1.id, c1.decryptedWithKeyId)
|
||||
assertEquals(syk1, c1.decryptedWithKey)
|
||||
|
||||
val data2 = "To push unpushinable".encodeToUByteArray()
|
||||
val c2 = Container.decode(c.updateData(data2).encoded)
|
||||
@ -61,7 +63,7 @@ class ContainerTest {
|
||||
assertContentEquals(data, d)
|
||||
assertTrue { c1.isDecrypted }
|
||||
assertEquals(p2.publicKey.id, c1.decryptedWithKeyId)
|
||||
assertEquals(p1.publicKey, c1.authorisedByKey)
|
||||
assertEquals(p2.secretKey, c1.decryptedWithKey)
|
||||
|
||||
val data2 = "To push unpushinable".encodeToUByteArray()
|
||||
val c2 = Container.decode(c.updateData(data2).encoded)
|
||||
@ -88,7 +90,7 @@ class ContainerTest {
|
||||
assertContentEquals(data, d)
|
||||
assertTrue { c1.isDecrypted }
|
||||
assertEquals(p4.publicKey.id, c1.decryptedWithKeyId)
|
||||
assertEquals(p1.publicKey, c1.authorisedByKey)
|
||||
assertEquals(p4.secretKey, c1.decryptedWithKey)
|
||||
|
||||
val data2 = "To push unpushinable".encodeToUByteArray()
|
||||
val c2 = Container.decode(c.updateData(data2).encoded)
|
||||
@ -338,4 +340,4 @@ class ContainerTest {
|
||||
expectOpen(data2, syk3, p3.secretKey, p4.secretKey)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,6 +241,28 @@ class KeysTest {
|
||||
assertContentEquals(clientSessionKey.sessionTag, serverSessionKey.sessionTag)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun sessionKeySerializationTest() = runTest {
|
||||
initCrypto()
|
||||
val ske = SafeKeyExchange()
|
||||
val cke = SafeKeyExchange()
|
||||
|
||||
val clientSessionKey = cke.clientSessionKey(ske.publicKey)
|
||||
val serverSessionKey = ske.serverSessionKey(cke.publicKey)
|
||||
|
||||
val restoredClientSessionKey = unpack<SafeKeyExchange.SessionKey>(pack(clientSessionKey))
|
||||
val restoredServerSessionKey = unpack<SafeKeyExchange.SessionKey>(pack(serverSessionKey))
|
||||
|
||||
assertEquals(clientSessionKey, restoredClientSessionKey)
|
||||
assertEquals(serverSessionKey, restoredServerSessionKey)
|
||||
assertContentEquals(clientSessionKey.sessionTag, restoredClientSessionKey.sessionTag)
|
||||
assertContentEquals(serverSessionKey.sessionTag, restoredServerSessionKey.sessionTag)
|
||||
|
||||
val src = "Hello from restored session keys!"
|
||||
assertEquals(src, restoredServerSessionKey.decryptString(restoredClientSessionKey.encrypt(src)))
|
||||
assertEquals(src, restoredClientSessionKey.decryptString(restoredServerSessionKey.encrypt(src)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun asymmetricKeyTest() = runTest {
|
||||
initCrypto()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user