From 96d1ce5da665ee88cacbc73f35f871d8231255e2 Mon Sep 17 00:00:00 2001 From: Alexis Sellier Date: Thu, 8 Dec 2022 13:18:33 +0100 Subject: [PATCH] crypto: Add ECDH trait and `MemorySigner` impl Signed-off-by: Alexis Sellier --- radicle-crypto/src/lib.rs | 10 ++++++++++ radicle-crypto/src/ssh/keystore.rs | 12 +++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/radicle-crypto/src/lib.rs b/radicle-crypto/src/lib.rs index 58b17547..6a73737a 100644 --- a/radicle-crypto/src/lib.rs +++ b/radicle-crypto/src/lib.rs @@ -26,6 +26,9 @@ pub struct Verified; #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct Unverified; +/// Output of a Diffie-Hellman key exchange. +pub type SharedSecret = [u8; 32]; + /// Error returned if signing fails, eg. due to an HSM or KMS. #[derive(Debug, Error)] #[error(transparent)] @@ -69,6 +72,13 @@ where } } +/// A signer that can perform Elliptic-curve Diffie–Hellman. +pub trait Ecdh: Signer { + /// Perform an ECDH key exchange. Takes the counter-party's public key, + /// and returns a computed shared secret. + fn ecdh(&self, other: &PublicKey) -> Result; +} + /// Cryptographic signature. #[derive(PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize)] #[serde(into = "String", try_from = "String")] diff --git a/radicle-crypto/src/ssh/keystore.rs b/radicle-crypto/src/ssh/keystore.rs index 893587af..bbff880d 100644 --- a/radicle-crypto/src/ssh/keystore.rs +++ b/radicle-crypto/src/ssh/keystore.rs @@ -5,7 +5,7 @@ use std::{fs, io}; use thiserror::Error; use zeroize::Zeroizing; -use crate::{keypair, PublicKey, SecretKey, Signature, Signer, SignerError}; +use crate::{keypair, Ecdh, PublicKey, SecretKey, SharedSecret, Signature, Signer, SignerError}; /// A secret key passphrase. pub type Passphrase = Zeroizing; @@ -139,6 +139,16 @@ impl Signer for MemorySigner { } } +impl Ecdh for MemorySigner { + fn ecdh(&self, other: &PublicKey) -> Result { + let pk = ed25519_compact::x25519::PublicKey::from_ed25519(other)?; + let sk = ed25519_compact::x25519::SecretKey::from_ed25519(&self.secret)?; + let ss = pk.dh(&sk)?; + + Ok(*ss) + } +} + impl MemorySigner { /// Load this signer from a keystore, given a secret key passphrase. pub fn load(keystore: &Keystore, passphrase: Passphrase) -> Result {