use std::{
io::{Read, Write},
marker::PhantomData,
};
use anyhow::Result;
#[cfg(feature = "chacha20")]
use chacha20::ChaCha20;
use cipher::{KeyIvInit, StreamCipher};
#[cfg(feature = "salsa20")]
use salsa20::Salsa20;
use crate::RwBuilder;
#[derive(Debug)]
pub struct Builder<B, C, K, N>
where
B: RwBuilder,
C: StreamCipher,
{
builder: B,
key: K,
nonce: N,
_marker: PhantomData<C>,
}
impl<B, C, K, N> Builder<B, C, K, N>
where
B: RwBuilder,
C: StreamCipher,
{
pub const fn new(builder: B, key: K, nonce: N) -> Self {
Self { builder, key, nonce, _marker: PhantomData }
}
}
#[cfg(feature = "chacha20")]
pub type ChaCha20Key = chacha20::Key;
#[cfg(feature = "chacha20")]
pub type ChaCha20Nonce = chacha20::Nonce;
#[cfg(feature = "chacha20")]
pub type ChaCha20Builder<B> = Builder<B, ChaCha20, ChaCha20Key, ChaCha20Nonce>;
#[cfg(feature = "salsa20")]
pub type Salsa20Key = salsa20::Key;
#[cfg(feature = "salsa20")]
pub type Salsa20Nonce = salsa20::Nonce;
#[cfg(feature = "salsa20")]
pub type Salsa20Builder<B> = Builder<B, Salsa20, Salsa20Key, Salsa20Nonce>;
trait CipherFactory<C> {
fn create_cipher(&self) -> C;
}
#[cfg(feature = "chacha20")]
impl<B> CipherFactory<ChaCha20> for Builder<B, ChaCha20, ChaCha20Key, ChaCha20Nonce>
where
B: RwBuilder,
{
fn create_cipher(&self) -> ChaCha20 {
ChaCha20::new(&self.key, &self.nonce)
}
}
#[cfg(feature = "salsa20")]
impl<B> CipherFactory<Salsa20> for Builder<B, Salsa20, Salsa20Key, Salsa20Nonce>
where
B: RwBuilder,
{
fn create_cipher(&self) -> Salsa20 {
Salsa20::new(&self.key, &self.nonce)
}
}
impl<B, C, K, N> RwBuilder for Builder<B, C, K, N>
where
B: RwBuilder,
C: StreamCipher,
Self: CipherFactory<C>,
{
type Reader = Reader<B::Reader, C>;
type Writer = Writer<B::Writer, C>;
fn reader(&self) -> Result<Self::Reader> {
let reader = self.builder.reader()?;
let cipher = self.create_cipher();
Ok(Reader { cipher, reader })
}
fn writer(&self) -> Result<Self::Writer> {
let writer = self.builder.writer()?;
let cipher = self.create_cipher();
Ok(Writer { cipher, writer })
}
}
#[derive(Debug)]
pub struct Reader<R, C>
where
R: Read,
C: StreamCipher,
{
cipher: C,
reader: R,
}
impl<R, C> Read for Reader<R, C>
where
R: Read,
C: StreamCipher,
{
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let bytes_read = self.reader.read(buf)?;
self.cipher
.try_apply_keystream(buf)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
Ok(bytes_read)
}
}
#[derive(Debug)]
pub struct Writer<W, C>
where
W: Write,
C: StreamCipher,
{
cipher: C,
writer: W,
}
impl<W, C> Write for Writer<W, C>
where
W: Write,
C: StreamCipher,
{
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let mut buffer = buf.to_owned();
self.cipher
.try_apply_keystream(buffer.as_mut_slice())
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
self.writer.write(buffer.as_slice())
}
fn flush(&mut self) -> std::io::Result<()> {
self.writer.flush()
}
}