From 42dbd9439268d5db83ec9410412735458bed2396 Mon Sep 17 00:00:00 2001 From: Avril Date: Tue, 10 Aug 2021 19:57:11 +0100 Subject: [PATCH] Start: `Source`: chacha20_poly1305 en/decryption wrapper over `io::Read` types. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TODO: `AsyncSource`: Async version of `Source`, and the `AsyncRead` couterpart of `AsyncSink`. TODO: `Stream`, `AsyncStream`: Combines both `Sink` and `Source` for `Read+Write` types (and async counterparts) using the same cipher key. Fortune for chacha20stream's current commit: Small curse − 小凶 --- Cargo.toml | 5 +++ src/stream.rs | 91 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 59 insertions(+), 37 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ebc2ed4..50ab298 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,11 @@ async = ["tokio", "pin-project"] # Explicitly clear in-memory buffers with `explicit_bzero()` instead of normal `bzero()`. explicit_clear = [] +# Reuse the output buffer for `Source`'s raw bytes read from the backing stream +# +# This can increase speed as no allocations are needed, however it can leak potentially sensitive data so is unsafe. +reuse-buffer = [] + # Build with C interface bindings ffi = ["libc"] diff --git a/src/stream.rs b/src/stream.rs index 989d59b..13d7bd4 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -56,56 +56,36 @@ pub type Error = ErrorStack; /// The `flush()` implementation *does* clear this buffer. /// You can use the `prune()` function to zero out this buffer manually too. //#[derive(Debug)] -pub struct Sink +pub struct Sink { - stream: W, crypter: Crypter, // for chacha, finalize does nothing it seems. we can also call it multiple times. - buffer: BufferVec, // used to buffer the operation + + stream: W, +} + +/// TODO: Document +//#[derive(Debug)] +pub struct Source +{ + crypter: Crypter, + #[cfg(not(feature="reuse-buffer"))] buffer: BufferVec, // When `reuse-buffer` is enabled, this isn't needed. We re-use the output buffer for the initial read of untransformed data from `stream` and the actual transformation of the read bytes. + + stream: R } -impl fmt::Debug for Sink +impl fmt::Debug for Sink { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Sink({:?}, ({} buffer cap))", self.stream, self.buffer.capacity()) + write!(f, "Sink({:?}, ({} buffer cap))", &self.stream, self.buffer.capacity()) } } -impl Sink +impl Sink where W: Write { - /// Create a new Chacha Sink stream wrapper - #[inline] fn new(stream: W, crypter: Crypter) -> Self - { - Self{stream, crypter, buffer: BufferVec::new()} - } - /// Create an encrypting Chacha Sink stream wrapper - pub fn encrypt(stream: W, key: Key, iv: IV) -> Result - { - Ok(Self::new(stream, cha::encrypter(key, iv)?)) - } - - /// Create a decrypting Chacha Sink stream wrapper - pub fn decrypt(stream: W, key: Key, iv: IV) -> Result - { - Ok(Self::new(stream, cha::decrypter(key, iv)?)) - } - - - /// Consume into the inner stream - #[inline] pub fn into_inner(self) -> W - { - self.stream - } - - /// Consume into the inner stream and crypter - #[inline] pub fn into_parts(self) -> (W, Crypter) - { - (self.stream, self.crypter) - } - /// The crypter of this instance #[inline] pub fn crypter(&self) -> &Crypter { @@ -162,7 +142,44 @@ where W: Write } } -impl Write for Sink +impl Sink +where W: Write +{ + /// Create a new Chacha Sink stream wrapper + #[inline] fn new(stream: W, crypter: Crypter) -> Self + { + Self{stream, crypter, buffer: BufferVec::new()} + } + + /// Create an encrypting Chacha Sink stream wrapper + pub fn encrypt(stream: W, key: Key, iv: IV) -> Result + { + Ok(Self::new(stream, cha::encrypter(key, iv)?)) + } + + /// Create a decrypting Chacha Sink stream wrapper + pub fn decrypt(stream: W, key: Key, iv: IV) -> Result + { + Ok(Self::new(stream, cha::decrypter(key, iv)?)) + } + + + /// Consume into the inner stream + #[inline] pub fn into_inner(self) -> W + { + self.stream + } + + /// Consume into the inner stream and crypter + #[inline] pub fn into_parts(self) -> (W, Crypter) + { + (self.stream, self.crypter) + } + + +} + +impl Write for Sink { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { let n = self.transform(buf)?;