From dc307c6d06c0cc2be4acc37977dd4747e0ff476e Mon Sep 17 00:00:00 2001 From: Avril Date: Mon, 16 Aug 2021 15:29:23 +0100 Subject: [PATCH] ESock: Added `split()` and `unsplit()` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TODO: Implement AsyncWrite/Read for the write/read halves TODO: Implement set_encrypted_write/read for the write/read halves Fortune for rsh's current commit: Half blessing − 半吉 --- src/sock/enc.rs | 77 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/src/sock/enc.rs b/src/sock/enc.rs index 1cccd2e..36a245d 100644 --- a/src/sock/enc.rs +++ b/src/sock/enc.rs @@ -182,7 +182,7 @@ pub struct ESock { impl ESock { - pub fn inner(&self) -> (&W, &R) + fn inner(&self) -> (&W, &R) { (self.tx.inner(), self.rx.inner()) } @@ -214,6 +214,79 @@ impl ESock { (self.state.encw, self.state.encr) } + + /// Create a new `ESock` wrapper over this writer and reader with this specific RSA key. + pub fn with_key(key: impl Into, tx: W, rx: R) -> Self + { + let (tk, tiv) = cha::keygen(); + Self { + info: ESockInfo::new(key), + state: Default::default(), + + // Note: These key+IV pairs are never used, as `state` defaults to unencrypted, and a new key/iv pair is generated when we `set_encrypted_write/read(true)`. + // TODO: Have a method to exchange these default session keys after `exchange()`? + tx: AsyncSink::encrypt(tx, tk, tiv).expect("Failed to create temp AsyncSink"), + rx: AsyncSource::encrypt(rx, tk, tiv).expect("Failed to create temp AsyncSource"), + } + } + /// Create a new `ESock` wrapper over this writer and reader with a newly generated private key + #[inline] pub fn new(tx: W, rx: R) -> Result + { + Ok(Self::with_key(RsaPrivateKey::generate()?, tx, rx)) + } + + /// The local RSA private key + #[inline] pub fn local_key(&self) -> &RsaPrivateKey + { + &self.info.us + } + /// THe remote RSA public key (if exchange has happened.) + #[inline] pub fn foreign_key(&self) -> Option<&RsaPublicKey> + { + self.info.them.as_ref() + } + + /// Split this `ESock` into a read+write pair. + /// + /// # Note + /// You must preform an `exchange()` before splitting, as exchanging RSA keys is not possible on a single half. + /// + /// It is also more efficient to `set_encrypted_write/read(true)` on `ESock` than it is on the halves, but changinc encryption modes on halves is still possible. + pub fn split(self) -> (ESockWriteHalf, ESockReadHalf) + { + let arced = Arc::new((self.info, RwLock::new(self.state))); + + (ESockWriteHalf(Arc::clone(&arced), self.tx), + ESockReadHalf(arced, self.rx)) + } + + /// Merge a previously split `ESock` into a single one again. + /// + /// # Panics + /// If the two halves were not split from the same `ESock`. + pub fn unsplit(txh: ESockWriteHalf, rxh: ESockReadHalf) -> Self + { + #[cold] + #[inline(never)] + fn _panic_ptr_ineq() -> ! + { + panic!("Cannot merge halves of different sockets") + } + if !Arc::ptr_eq(&txh.0, &rxh.0) { + _panic_ptr_ineq(); + } + + let tx = txh.1; + drop(txh.0); + let (info, lstate) = Arc::try_unwrap(rxh.0).unwrap(); + let rx = rxh.1; + + Self { + state: lstate.into_inner(), + info, + tx, rx + } + } } impl ESock @@ -235,6 +308,7 @@ impl ESock }) } /// Enable write encryption + //TODO: Implement this also for write half pub async fn set_encrypted_write(&mut self, set: bool) -> eyre::Result<()> { use tokio::prelude::*; @@ -268,6 +342,7 @@ impl ESock /// Enable read encryption /// /// The other endpoint must have sent a `set_encrypted_write()` + //TODO: Implement this also for read half pub async fn set_encrypted_read(&mut self, set: bool) -> eyre::Result<()> { use tokio::prelude::*;