Added support for SafeKeyExchange serialization/deserialization and associated tests.
This commit is contained in:
parent
cd57627cdb
commit
d6b171229f
@ -11,7 +11,14 @@
|
|||||||
package net.sergeych.crypto2
|
package net.sergeych.crypto2
|
||||||
|
|
||||||
import com.ionspin.kotlin.crypto.keyexchange.KeyExchange
|
import com.ionspin.kotlin.crypto.keyexchange.KeyExchange
|
||||||
|
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.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
import net.sergeych.crypto2.SafeKeyExchange.SessionKey
|
import net.sergeych.crypto2.SafeKeyExchange.SessionKey
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,9 +38,44 @@ import net.sergeych.crypto2.SafeKeyExchange.SessionKey
|
|||||||
* - while it is possible to generate several keys "ahead", the care should be taken when storing them,
|
* - while it is possible to generate several keys "ahead", the care should be taken when storing them,
|
||||||
* encrypt it with some other key to maintain safety.
|
* encrypt it with some other key to maintain safety.
|
||||||
* - do not use [EncryptingPublicKey] for anything but creating session keys.
|
* - do not use [EncryptingPublicKey] for anything but creating session keys.
|
||||||
|
* - the serialized form includes the secret exchange key, so it should be encrypted when stored.
|
||||||
*/
|
*/
|
||||||
class SafeKeyExchange {
|
@Serializable(with = SafeKeyExchange.SafeKeyExchangeSerializer::class)
|
||||||
private val pair = KeyExchange.keypair()
|
class SafeKeyExchange private constructor(
|
||||||
|
private val pair: KeyExchangeKeyPair,
|
||||||
|
) {
|
||||||
|
|
||||||
|
constructor() : this(KeyExchange.keypair())
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
private class Packed(
|
||||||
|
val publicKey: UByteArray,
|
||||||
|
val secretKey: UByteArray,
|
||||||
|
)
|
||||||
|
|
||||||
|
object SafeKeyExchangeSerializer : KSerializer<SafeKeyExchange> {
|
||||||
|
private val packedSerializer = Packed.serializer()
|
||||||
|
|
||||||
|
override val descriptor: SerialDescriptor = packedSerializer.descriptor
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: SafeKeyExchange) {
|
||||||
|
encoder.encodeSerializableValue(
|
||||||
|
packedSerializer,
|
||||||
|
Packed(value.pair.publicKey, value.pair.secretKey)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): SafeKeyExchange {
|
||||||
|
val packed = decoder.decodeSerializableValue(packedSerializer)
|
||||||
|
require(packed.publicKey.size == crypto_kx_PUBLICKEYBYTES) {
|
||||||
|
"SafeKeyExchange public key must be $crypto_kx_PUBLICKEYBYTES bytes"
|
||||||
|
}
|
||||||
|
require(packed.secretKey.size == crypto_kx_SECRETKEYBYTES) {
|
||||||
|
"SafeKeyExchange secret key must be $crypto_kx_SECRETKEYBYTES bytes"
|
||||||
|
}
|
||||||
|
return SafeKeyExchange(KeyExchangeKeyPair(packed.publicKey, packed.secretKey))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The session key. It uses a pair of keys to encrypt and decrypt messages to maintain high
|
* The session key. It uses a pair of keys to encrypt and decrypt messages to maintain high
|
||||||
@ -90,9 +132,24 @@ class SafeKeyExchange {
|
|||||||
* The public key; it should be transmitted to the other party, this is serializable.
|
* 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
|
* Do not use it except to get [SessionKey] with [clientSessionKey] or [serverSessionKey]. Storing and reusing
|
||||||
* it is a great danger.
|
* it is a great danger.
|
||||||
|
*
|
||||||
|
* Instances can be compared and used as hashtable keys.
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
class PublicKey(val keyBytes: UByteArray)
|
class PublicKey(val keyBytes: UByteArray) {
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (other == null || this::class != other::class) return false
|
||||||
|
|
||||||
|
other as PublicKey
|
||||||
|
|
||||||
|
return keyBytes.contentEquals(other.keyBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return keyBytes.contentHashCode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The public key to be sent to the other party. When received, get the session keys with [clientSessionKey]
|
* The public key to be sent to the other party. When received, get the session keys with [clientSessionKey]
|
||||||
|
|||||||
@ -221,6 +221,26 @@ class KeysTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun keyExchangeSerializationTest() = runTest {
|
||||||
|
initCrypto()
|
||||||
|
val ske = SafeKeyExchange()
|
||||||
|
val packedExchange = pack(ske)
|
||||||
|
|
||||||
|
val cke = SafeKeyExchange()
|
||||||
|
val clientSessionKey = cke.clientSessionKey(ske.publicKey)
|
||||||
|
|
||||||
|
val restoredExchange = unpack<SafeKeyExchange>(packedExchange)
|
||||||
|
assertEquals(ske.publicKey, restoredExchange.publicKey)
|
||||||
|
|
||||||
|
val serverSessionKey = restoredExchange.serverSessionKey(cke.publicKey)
|
||||||
|
|
||||||
|
val src = "Hello after restore!"
|
||||||
|
assertEquals(src, serverSessionKey.decryptString(clientSessionKey.encrypt(src)))
|
||||||
|
assertEquals(src, clientSessionKey.decryptString(serverSessionKey.encrypt(src)))
|
||||||
|
assertContentEquals(clientSessionKey.sessionTag, serverSessionKey.sessionTag)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun asymmetricKeyTest() = runTest {
|
fun asymmetricKeyTest() = runTest {
|
||||||
initCrypto()
|
initCrypto()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user