From bb815afcaaf0a2a727fc94735cee24a8fb197c41 Mon Sep 17 00:00:00 2001 From: Oleg Yukhnevich Date: Sun, 28 Jul 2024 00:43:30 +0300 Subject: [PATCH] WIP ECDH --- .../kotlin/algorithms/asymmetric/ECDH.kt | 6 +++-- .../kotlin/operations/SecretDerivation.kt | 23 +++++++++++++++++++ .../operations/SharedSecretDerivation.kt | 14 ----------- .../asymmetric/EcdhCompatibilityTest.kt | 16 ++++++------- .../src/jvmMain/kotlin/algorithms/JdkEcdh.kt | 19 ++++++++------- .../kotlin/algorithms/Openssl3Ecdh.kt | 19 +++++++-------- .../kotlin/algorithms/WebCryptoEcdh.kt | 12 +++++----- 7 files changed, 60 insertions(+), 49 deletions(-) create mode 100644 cryptography-core/src/commonMain/kotlin/operations/SecretDerivation.kt delete mode 100644 cryptography-core/src/commonMain/kotlin/operations/SharedSecretDerivation.kt diff --git a/cryptography-core/src/commonMain/kotlin/algorithms/asymmetric/ECDH.kt b/cryptography-core/src/commonMain/kotlin/algorithms/asymmetric/ECDH.kt index c96bdaf9..bdd28973 100644 --- a/cryptography-core/src/commonMain/kotlin/algorithms/asymmetric/ECDH.kt +++ b/cryptography-core/src/commonMain/kotlin/algorithms/asymmetric/ECDH.kt @@ -18,11 +18,13 @@ public interface ECDH : EC { @SubclassOptInRequired(CryptographyProviderApi::class) public interface PublicKey : EC.PublicKey { - public fun sharedSecretDerivation(): SharedSecretDerivation + public fun secretDerivation(): SecretDerivation + public fun asyncSecretDerivation(): AsyncSecretDerivation } @SubclassOptInRequired(CryptographyProviderApi::class) public interface PrivateKey : EC.PrivateKey { - public fun sharedSecretDerivation(): SharedSecretDerivation + public fun secretDerivation(): SecretDerivation + public fun asyncSecretDerivation(): AsyncSecretDerivation } } diff --git a/cryptography-core/src/commonMain/kotlin/operations/SecretDerivation.kt b/cryptography-core/src/commonMain/kotlin/operations/SecretDerivation.kt new file mode 100644 index 00000000..a9763db5 --- /dev/null +++ b/cryptography-core/src/commonMain/kotlin/operations/SecretDerivation.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license. + */ + +package dev.whyoleg.cryptography.operations + +import dev.whyoleg.cryptography.* +import dev.whyoleg.cryptography.materials.key.* + +@SubclassOptInRequired(CryptographyProviderApi::class) +public interface SecretDerivation { + public fun deriveSecret(other: K): ByteArray +} + +@SubclassOptInRequired(CryptographyProviderApi::class) +public interface AsyncSecretDerivation { + public suspend fun deriveSecret(other: K): ByteArray +} + +@CryptographyProviderApi +public fun SecretDerivation.asAsync(): AsyncSecretDerivation = object : AsyncSecretDerivation { + override suspend fun deriveSecret(other: K): ByteArray = this@asAsync.deriveSecret(other) +} diff --git a/cryptography-core/src/commonMain/kotlin/operations/SharedSecretDerivation.kt b/cryptography-core/src/commonMain/kotlin/operations/SharedSecretDerivation.kt deleted file mode 100644 index 8ed6313f..00000000 --- a/cryptography-core/src/commonMain/kotlin/operations/SharedSecretDerivation.kt +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license. - */ - -package dev.whyoleg.cryptography.operations - -import dev.whyoleg.cryptography.* -import dev.whyoleg.cryptography.materials.key.* - -@SubclassOptInRequired(CryptographyProviderApi::class) -public interface SharedSecretDerivation { - public suspend fun deriveSharedSecret(other: K): ByteArray - public fun deriveSharedSecretBlocking(other: K): ByteArray -} diff --git a/cryptography-providers-tests/src/commonMain/kotlin/algorithms/asymmetric/EcdhCompatibilityTest.kt b/cryptography-providers-tests/src/commonMain/kotlin/algorithms/asymmetric/EcdhCompatibilityTest.kt index 499ab7d7..2b303ee9 100644 --- a/cryptography-providers-tests/src/commonMain/kotlin/algorithms/asymmetric/EcdhCompatibilityTest.kt +++ b/cryptography-providers-tests/src/commonMain/kotlin/algorithms/asymmetric/EcdhCompatibilityTest.kt @@ -32,10 +32,10 @@ abstract class EcdhCompatibilityTest( ) { otherKeyPair, otherKeyReference, _ -> val secrets = listOf( - keyPair.privateKey.sharedSecretDerivation().deriveSharedSecret(otherKeyPair.publicKey), - keyPair.publicKey.sharedSecretDerivation().deriveSharedSecret(otherKeyPair.privateKey), - otherKeyPair.privateKey.sharedSecretDerivation().deriveSharedSecret(keyPair.publicKey), - otherKeyPair.publicKey.sharedSecretDerivation().deriveSharedSecret(keyPair.privateKey), + keyPair.privateKey.secretDerivation().deriveSharedSecret(otherKeyPair.publicKey), + keyPair.publicKey.secretDerivation().deriveSharedSecret(otherKeyPair.privateKey), + otherKeyPair.privateKey.secretDerivation().deriveSharedSecret(keyPair.publicKey), + otherKeyPair.publicKey.secretDerivation().deriveSharedSecret(keyPair.privateKey), ) repeat(secrets.size) { i -> @@ -69,12 +69,12 @@ abstract class EcdhCompatibilityTest( otherPrivateKeys.forEach { otherPrivateKey -> assertContentEquals( sharedSecret, - publicKey.sharedSecretDerivation().deriveSharedSecret(otherPrivateKey), + publicKey.secretDerivation().deriveSharedSecret(otherPrivateKey), "Public + Other Private" ) assertContentEquals( sharedSecret, - otherPrivateKey.sharedSecretDerivation().deriveSharedSecret(publicKey), + otherPrivateKey.secretDerivation().deriveSharedSecret(publicKey), "Other Private + Public" ) } @@ -83,12 +83,12 @@ abstract class EcdhCompatibilityTest( otherPublicKeys.forEach { otherPublicKey -> assertContentEquals( sharedSecret, - otherPublicKey.sharedSecretDerivation().deriveSharedSecret(privateKey), + otherPublicKey.secretDerivation().deriveSharedSecret(privateKey), "Other Public + Private" ) assertContentEquals( sharedSecret, - privateKey.sharedSecretDerivation().deriveSharedSecret(otherPublicKey), + privateKey.secretDerivation().deriveSharedSecret(otherPublicKey), "Private + Other Public" ) } diff --git a/cryptography-providers/jdk/src/jvmMain/kotlin/algorithms/JdkEcdh.kt b/cryptography-providers/jdk/src/jvmMain/kotlin/algorithms/JdkEcdh.kt index b1a2f9d1..b61e543a 100644 --- a/cryptography-providers/jdk/src/jvmMain/kotlin/algorithms/JdkEcdh.kt +++ b/cryptography-providers/jdk/src/jvmMain/kotlin/algorithms/JdkEcdh.kt @@ -22,23 +22,26 @@ internal class JdkEcdh(state: JdkCryptographyState) : JdkEc = EcdhPublicKeySecretDerivation(state, key) + override fun secretDerivation(): SecretDerivation = EcdhPublicKeySecretDerivation(state, key) + override fun asyncSecretDerivation(): AsyncSecretDerivation { + TODO("Not yet implemented") + } } private class EcdhPrivateKey( private val state: JdkCryptographyState, val key: JPrivateKey, ) : ECDH.PrivateKey, BaseEcPrivateKey(key) { - override fun sharedSecretDerivation(): SharedSecretDerivation = EcdhPrivateKeySecretDerivation(state, key) + override fun secretDerivation(): SecretDerivation = EcdhPrivateKeySecretDerivation(state, key) } private class EcdhPublicKeySecretDerivation( private val state: JdkCryptographyState, private val publicKey: JPublicKey, - ) : SharedSecretDerivation { + ) : SecretDerivation { private val keyAgreement = state.keyAgreement("ECDH") - override fun deriveSharedSecretBlocking(other: ECDH.PrivateKey): ByteArray { + override fun deriveSecret(other: ECDH.PrivateKey): ByteArray { check(other is EcdhPrivateKey) { "Only ${EcdhPrivateKey::class} supported" } return keyAgreement.use { @@ -48,16 +51,16 @@ internal class JdkEcdh(state: JdkCryptographyState) : JdkEc { + ) : SecretDerivation { private val keyAgreement = state.keyAgreement("ECDH") - override fun deriveSharedSecretBlocking(other: ECDH.PublicKey): ByteArray { + override fun deriveSecret(other: ECDH.PublicKey): ByteArray { check(other is EcdhPublicKey) { "Only ${EcdhPublicKey::class} supported" } return keyAgreement.use { @@ -67,6 +70,6 @@ internal class JdkEcdh(state: JdkCryptographyState) : JdkEc, - ) : ECDH.PrivateKey, Openssl3PrivateKeyEncodable(key), SharedSecretDerivation { + ) : ECDH.PrivateKey, Openssl3PrivateKeyEncodable(key), SecretDerivation { override fun outputType(format: EC.PrivateKey.Format): String = when (format) { EC.PrivateKey.Format.DER, EC.PrivateKey.Format.DER.SEC1 -> "DER" EC.PrivateKey.Format.PEM, EC.PrivateKey.Format.PEM.SEC1 -> "PEM" @@ -94,20 +94,18 @@ internal object Openssl3Ecdh : ECDH { else -> super.outputStruct(format) } - override fun sharedSecretDerivation(): SharedSecretDerivation = this + override fun secretDerivation(): SecretDerivation = this + override fun asyncSecretDerivation(): AsyncSecretDerivation = asAsync() - override fun deriveSharedSecretBlocking(other: ECDH.PublicKey): ByteArray { + override fun deriveSecret(other: ECDH.PublicKey): ByteArray { check(other is EcPublicKey) - return deriveSharedSecret(publicKey = other.key, privateKey = key) } - - override suspend fun deriveSharedSecret(other: ECDH.PublicKey): ByteArray = deriveSharedSecretBlocking(other) } private class EcPublicKey( key: CPointer, - ) : ECDH.PublicKey, Openssl3PublicKeyEncodable(key), SharedSecretDerivation { + ) : ECDH.PublicKey, Openssl3PublicKeyEncodable(key), SecretDerivation { override fun outputType(format: EC.PublicKey.Format): String = when (format) { EC.PublicKey.Format.DER -> "DER" EC.PublicKey.Format.PEM -> "PEM" @@ -120,15 +118,14 @@ internal object Openssl3Ecdh : ECDH { else -> super.encodeToBlocking(format) } - override fun sharedSecretDerivation(): SharedSecretDerivation = this + override fun secretDerivation(): SecretDerivation = this + override fun asyncSecretDerivation(): AsyncSecretDerivation = asAsync() - override fun deriveSharedSecretBlocking(other: ECDH.PrivateKey): ByteArray { + override fun deriveSecret(other: ECDH.PrivateKey): ByteArray { check(other is EcPrivateKey) return deriveSharedSecret(publicKey = key, privateKey = other.key) } - - override suspend fun deriveSharedSecret(other: ECDH.PrivateKey): ByteArray = deriveSharedSecretBlocking(other) } } diff --git a/cryptography-providers/webcrypto/src/commonMain/kotlin/algorithms/WebCryptoEcdh.kt b/cryptography-providers/webcrypto/src/commonMain/kotlin/algorithms/WebCryptoEcdh.kt index 945708fb..3bee4249 100644 --- a/cryptography-providers/webcrypto/src/commonMain/kotlin/algorithms/WebCryptoEcdh.kt +++ b/cryptography-providers/webcrypto/src/commonMain/kotlin/algorithms/WebCryptoEcdh.kt @@ -22,8 +22,8 @@ internal object WebCryptoEcdh : WebCryptoEc { - override fun sharedSecretDerivation(): SharedSecretDerivation = this + ) : EcPublicKey(publicKey), ECDH.PublicKey, SecretDerivation { + override fun secretDerivation(): SecretDerivation = this override suspend fun deriveSharedSecret(other: ECDH.PrivateKey): ByteArray { check(other is EcdhPrivateKey) @@ -34,13 +34,13 @@ internal object WebCryptoEcdh : WebCryptoEc { - override fun sharedSecretDerivation(): SharedSecretDerivation = this + ) : EcPrivateKey(privateKey), ECDH.PrivateKey, SecretDerivation { + override fun secretDerivation(): SecretDerivation = this override suspend fun deriveSharedSecret(other: ECDH.PublicKey): ByteArray { check(other is EcdhPublicKey) return WebCrypto.deriveBits( @@ -50,6 +50,6 @@ internal object WebCryptoEcdh : WebCryptoEc