use openssl::error::ErrorStack;
use openssl::symm::{Cipher, Crypter, Mode};
use std::io::{BufRead, Error, ErrorKind, Read};
const EVP_MAX_BLOCK_LENGTH: usize = 32;
const BUFFER_SIZE: usize = EVP_MAX_BLOCK_LENGTH * 2;
struct Buffer {
buffer: [u8; BUFFER_SIZE],
write_index: usize,
read_index: usize,
}
impl Default for Buffer {
fn default() -> Self {
Self {
buffer: [0u8; BUFFER_SIZE],
write_index: 0,
read_index: 0,
}
}
}
impl<'a> Buffer {
fn len(&self) -> usize {
self.write_index - self.read_index
}
fn is_empty(&self) -> bool {
self.write_index == self.read_index
}
fn fill<F, E>(&mut self, mut read: F) -> Result<usize, E>
where
F: FnMut(&mut [u8]) -> Result<usize, E>,
{
let written = read(&mut self.buffer[self.write_index..])?;
self.write_index += written;
Ok(written)
}
fn reset(&mut self) {
self.read_index = 0;
self.write_index = 0;
}
}
impl Read for Buffer {
fn read(&mut self, dst: &mut [u8]) -> std::io::Result<usize> {
let len = std::cmp::min(dst.len(), self.len());
dst[..len].copy_from_slice(&self.buffer[self.read_index..][..len]);
self.read_index += len;
Ok(len)
}
}
#[test]
fn zero_len_buffer_read() {
let mut b = Buffer::default();
let mut temp = Vec::new();
match b.read(&mut temp) {
Ok(0) => {}
_ => panic!("Zero-length read failure!"),
}
}
struct Cryptostream<R: Read> {
reader: R,
read_buffer: [u8; BUFFER_SIZE],
write_buffer: Buffer,
never_used: bool,
cipher: Cipher,
crypter: Crypter,
finalized: bool,
}
impl<R: Read> Cryptostream<R> {
pub fn new(
mode: Mode,
reader: R,
cipher: Cipher,
key: &[u8],
iv: &[u8],
) -> Result<Self, ErrorStack> {
let mut crypter = Crypter::new(cipher, mode, key, Some(iv))?;
crypter.pad(true);
Ok(Self {
reader: reader,
read_buffer: [0; BUFFER_SIZE],
write_buffer: Default::default(),
never_used: true,
cipher: cipher.clone(),
crypter: crypter,
finalized: false,
})
}
pub fn finish(self) -> R {
self.reader
}
}
impl<R: Read> Read for Cryptostream<R> {
fn read(&mut self, mut buf: &mut [u8]) -> Result<usize, Error> {
let block_size = self.cipher.block_size();
debug_assert!(
block_size.count_ones() == 1,
"Only algorithms with power-of-two block sizes are supported!"
);
if !self.write_buffer.is_empty() {
let drained = self.write_buffer.read(&mut buf)?;
return Ok(drained);
}
if self.finalized {
return Ok(0);
}
let mut bytes_read = 0;
loop {
let max_read = self.read_buffer.len() - bytes_read - block_size;
let mut read_buffer = &mut self.read_buffer[bytes_read..][..max_read];
match self.reader.read(&mut read_buffer) {
Ok(0) => {
self.finalized = true;
return if self.never_used {
Ok(0)
} else if !self.write_buffer.is_empty() || buf.len() < bytes_read + block_size {
let write_buffer = &mut self.write_buffer;
let crypter = &mut self.crypter;
write_buffer
.fill(|b| crypter.finalize(b))
.map_err(|e| Error::new(ErrorKind::Other, e))?;
self.write_buffer.read(buf)
} else {
self.crypter
.finalize(&mut buf)
.map_err(|e| Error::new(ErrorKind::Other, e))
};
}
Ok(n) => {
self.never_used = false;
let old_bytes_read = bytes_read;
bytes_read += n;
debug_assert!(self.write_buffer.is_empty());
if buf.len() < n + block_size {
let write_buffer = &mut self.write_buffer;
let crypter = &mut self.crypter;
write_buffer.reset();
let bytes_written = write_buffer
.fill(|b| crypter.update(&read_buffer[old_bytes_read..bytes_read], b))
.map_err(|e| Error::new(ErrorKind::Other, e))?;
match bytes_written {
0 => continue,
_ => return self.write_buffer.read(&mut buf),
};
} else {
match self
.crypter
.update(&self.read_buffer[old_bytes_read..bytes_read], &mut buf)?
{
0 => continue,
written => return Ok(written),
};
};
}
Err(e) => return Err(e),
};
}
}
}
pub struct Encryptor<R: BufRead> {
inner: Cryptostream<R>,
}
impl<R: BufRead> Encryptor<R> {
pub fn new(reader: R, cipher: Cipher, key: &[u8], iv: &[u8]) -> Result<Self, ErrorStack> {
Ok(Self {
inner: Cryptostream::new(Mode::Encrypt, reader, cipher, key, iv)?,
})
}
pub fn finish(self) -> R {
self.inner.reader
}
}
impl<R: BufRead> Read for Encryptor<R> {
fn read(&mut self, mut buf: &mut [u8]) -> Result<usize, Error> {
self.inner.read(&mut buf)
}
}
pub struct Decryptor<R: BufRead> {
inner: Cryptostream<R>,
}
impl<R: BufRead> Decryptor<R> {
pub fn new(reader: R, cipher: Cipher, key: &[u8], iv: &[u8]) -> Result<Self, ErrorStack> {
Ok(Self {
inner: Cryptostream::new(Mode::Decrypt, reader, cipher, key, iv)?,
})
}
pub fn finish(self) -> R {
self.inner.finish()
}
}
impl<R: BufRead> Read for Decryptor<R> {
fn read(&mut self, mut buf: &mut [u8]) -> Result<usize, Error> {
self.inner.read(&mut buf)
}
}