ESock: Added `split()` and `unsplit()`

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 − 半吉
master
Avril 3 years ago
parent edeb2ffee7
commit dc307c6d06
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -182,7 +182,7 @@ pub struct ESock<W, R> {
impl<W: AsyncWrite, R: AsyncRead> ESock<W, R> impl<W: AsyncWrite, R: AsyncRead> ESock<W, R>
{ {
pub fn inner(&self) -> (&W, &R) fn inner(&self) -> (&W, &R)
{ {
(self.tx.inner(), self.rx.inner()) (self.tx.inner(), self.rx.inner())
} }
@ -214,6 +214,79 @@ impl<W: AsyncWrite, R: AsyncRead> ESock<W, R>
{ {
(self.state.encw, self.state.encr) (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<RsaPrivateKey>, 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<Self, rsa::Error>
{
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<W>, ESockReadHalf<R>)
{
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<W>, rxh: ESockReadHalf<R>) -> 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<W: AsyncWrite+ Unpin, R: AsyncRead + Unpin> ESock<W, R> impl<W: AsyncWrite+ Unpin, R: AsyncRead + Unpin> ESock<W, R>
@ -235,6 +308,7 @@ impl<W: AsyncWrite+ Unpin, R: AsyncRead + Unpin> ESock<W, R>
}) })
} }
/// Enable write encryption /// Enable write encryption
//TODO: Implement this also for write half
pub async fn set_encrypted_write(&mut self, set: bool) -> eyre::Result<()> pub async fn set_encrypted_write(&mut self, set: bool) -> eyre::Result<()>
{ {
use tokio::prelude::*; use tokio::prelude::*;
@ -268,6 +342,7 @@ impl<W: AsyncWrite+ Unpin, R: AsyncRead + Unpin> ESock<W, R>
/// Enable read encryption /// Enable read encryption
/// ///
/// The other endpoint must have sent a `set_encrypted_write()` /// 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<()> pub async fn set_encrypted_read(&mut self, set: bool) -> eyre::Result<()>
{ {
use tokio::prelude::*; use tokio::prelude::*;

Loading…
Cancel
Save