use openssl::error::ErrorStack;
use openssl::symm::{Cipher, Crypter, Mode};
use std::io::{Error, ErrorKind, Write};
const BUFFER_SIZE: usize = 4096;
struct Cryptostream<W: Write> {
buffer: [u8; BUFFER_SIZE],
writer: Option<W>,
cipher: Cipher,
crypter: Crypter,
finalized: bool,
never_used: bool,
}
impl<W: Write> Cryptostream<W> {
pub fn new(
mode: Mode,
writer: W,
cipher: Cipher,
key: &[u8],
iv: &[u8],
) -> Result<Self, ErrorStack> {
let mut crypter = Crypter::new(cipher, mode, key, Some(iv))?;
crypter.pad(true);
Ok(Self {
buffer: [0u8; BUFFER_SIZE],
writer: Some(writer),
never_used: true,
cipher: cipher.clone(),
crypter: crypter,
finalized: false,
})
}
fn inner_finish(&mut self) -> Result<(), Error> {
if !self.finalized {
self.finalized = true;
if !self.never_used {
let mut buffer = [0u8; 16];
let bytes_written = self
.crypter
.finalize(&mut buffer)
.map_err(|e| Error::new(ErrorKind::Other, e))?;
self.writer
.as_mut()
.unwrap()
.write(&buffer[0..bytes_written])?;
}
}
self.flush()
}
pub fn finish(mut self) -> Result<W, Error> {
self.inner_finish()?;
let mut inner = None;
std::mem::swap::<Option<W>>(&mut self.writer, &mut inner);
Ok(inner.unwrap())
}
}
impl<W: Write> Write for Cryptostream<W> {
fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
if self.finalized {
return Ok(0);
}
let block_size = self.cipher.block_size();
let max_read = std::cmp::min(BUFFER_SIZE - block_size, buf.len());
if max_read > 0 {
let bytes_encrypted = self
.crypter
.update(&buf[0..max_read], &mut self.buffer)
.map_err(|e| Error::new(ErrorKind::Other, e))?;
self.never_used = false;
self.writer
.as_mut()
.unwrap()
.write_all(&self.buffer[0..bytes_encrypted])?;
}
Ok(max_read)
}
fn flush(&mut self) -> Result<(), Error> {
match self.writer.as_mut() {
Some(x) => x.flush(),
_ => Ok(()),
}
}
}
impl<W: Write> Drop for Cryptostream<W> {
fn drop(&mut self) {
let _r = self.inner_finish();
}
}
pub struct Encryptor<W: Write> {
inner: Cryptostream<W>,
}
impl<W: Write> Encryptor<W> {
pub fn new(writer: W, cipher: Cipher, key: &[u8], iv: &[u8]) -> Result<Self, ErrorStack> {
Ok(Self {
inner: Cryptostream::new(Mode::Encrypt, writer, cipher, key, iv)?,
})
}
pub fn finish(self) -> Result<W, Error> {
self.inner.finish()
}
}
impl<W: Write> Write for Encryptor<W> {
fn write(&mut self, mut buf: &[u8]) -> Result<usize, Error> {
self.inner.write(&mut buf)
}
fn flush(&mut self) -> Result<(), Error> {
self.inner.flush()
}
}
pub struct Decryptor<W: Write> {
inner: Cryptostream<W>,
}
impl<W: Write> Decryptor<W> {
pub fn new(writer: W, cipher: Cipher, key: &[u8], iv: &[u8]) -> Result<Self, ErrorStack> {
Ok(Self {
inner: Cryptostream::new(Mode::Decrypt, writer, cipher, key, iv)?,
})
}
pub fn finish(self) -> Result<W, Error> {
self.inner.finish()
}
}
impl<W: Write> Write for Decryptor<W> {
fn write(&mut self, mut buf: &[u8]) -> Result<usize, Error> {
self.inner.write(&mut buf)
}
fn flush(&mut self) -> Result<(), Error> {
self.inner.flush()
}
}