Skip to content

Instantly share code, notes, and snippets.

@timvisee
Last active January 30, 2019 21:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save timvisee/7f7fe22c501195987156f09b92f7b78a to your computer and use it in GitHub Desktop.
Save timvisee/7f7fe22c501195987156f09b92f7b78a to your computer and use it in GitHub Desktop.
use std::cmp;
use std::io::{self, BufRead, BufReader, Cursor, Error as IoError, Read, Write};
use bytes::{BufMut, BytesMut};
use ece::Aes128GcmEceWebPush;
/// The cryptographic mode for a crypter: encrypt or decrypt.
pub enum CryptMode {
/// Encrypt data while transforming.
Encrypt,
/// Decrypt data while transforming.
Decrypt,
}
/// Something that can encrypt or decrypt given data.
pub trait Crypt: Sized {
/// The wrapping reader type used for this cryptographic type.
type Reader: CryptRead<Self>;
/// The wrapping writer type used for this cryptographic type.
type Writer: CryptWrite<Self>;
/// Wrap the `inner` reader, bytes that are read are transformed with this cryptographic configuration.
fn reader(self, inner: Box<dyn Read>) -> Self::Reader {
Self::Reader::new(self, inner)
}
/// Wrap the `inner` writer, bytes that are read are transformed with this cryptographic configuration.
fn writer(self, inner: Box<dyn Write>) -> Self::Writer {
Self::Writer::new(self, inner)
}
/// Read bytes from the given input buffer, transform it using the configured cryptography and
/// return transformed data when available.
///
/// This returns a tuple with the number of bytes read from the `input`, along with transformed
/// data if available in the following format: `(read_bytes, transformed_data)`.
fn crypt(&mut self, input: &[u8]) -> (usize, Option<Vec<u8>>);
}
/// A reader wrapping another reader, to encrypt or decrypt data read from it.
pub trait CryptRead<C>: Read
where C: Crypt,
{
/// Wrap the given `inner` reader, transform data using `crypt`.
fn new(crypt: C, inner: Box<dyn Read>) -> Self;
}
/// A writer wrapping another writher, to encrypt or decrypt data it is writen to.
pub trait CryptWrite<C>: Write
where C: Crypt,
{
/// Wrap the given `inner` writer, transform data using `crypt`.
fn new(crypt: C, inner: Box<dyn Write>) -> Self;
}
pub struct EceReader {
crypt: EceCrypt,
inner: Box<dyn Read>,
buf_in: BytesMut,
buf_out: BytesMut,
}
pub struct EceWriter {
crypt: EceCrypt,
inner: Box<dyn Write>,
buf: BytesMut,
}
impl CryptRead<EceCrypt> for EceReader {
fn new(crypt: EceCrypt, inner: Box<dyn Read>) -> Self {
Self {
crypt,
inner,
// TODO: use proper buffer size
buf_in: BytesMut::new(),
buf_out: BytesMut::new(),
}
}
}
impl Read for EceReader {
fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
// Number of bytes written to given buffer
let mut total = 0;
// Write any output buffer bytes first
if !self.buf_out.is_empty() {
// Copy as much as possible from inner to output buffer, increase total
let write = cmp::min(self.buf_out.len(), buf.len());
total += write;
buf[..write].copy_from_slice(&self.buf_out.split_to(write));
// Return if given buffer is full, or slice to unwritten buffer
if total >= buf.len() {
return Ok(total);
}
buf = &mut buf[write..];
}
// Attempt to fill input buffer if has capacity
let capacity = self.buf_in.capacity() - self.buf_in.len();
if capacity > 0 {
// Read from inner to input buffer
let mut inner_buf = vec![0u8; capacity];
let read = self.inner.read(&mut inner_buf)?;
self.buf_in.put(inner_buf);
// If not enough input buffer data, we can't crypt, read nothing
if read < capacity {
return Ok(0);
}
}
// Move input buffer into the crypter
let (read, out) = self.crypt.crypt(&self.buf_in);
self.buf_in.split_to(read);
// Write any crypter output to given buffer and remaining to output buffer
if let Some(out) = out {
// Copy as much data as possible from crypter output to read buffer
let write = cmp::min(out.len(), buf.len());
total += write;
buf[..write].copy_from_slice(&out[..write]);
// Copy remaining bytes into output buffer
if write < out.len() {
self.buf_out.extend_from_slice(&out[write..]);
}
// Return if given buffer is full, or slice to unwritten buffer
if write >= buf.len() {
return Ok(total);
}
buf = &mut buf[write..];
}
// Try again with remaining given buffer
self.read(buf).map(|n| n + total)
}
}
impl CryptWrite<EceCrypt> for EceWriter {
fn new(crypt: EceCrypt, inner: Box<dyn Write>) -> Self {
Self {
crypt,
inner,
// TODO: use proper buffer size
buf: BytesMut::new(),
}
}
}
impl Write for EceWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
// TODO: implement reader
panic!("not yet implemented");
}
fn flush(&mut self) -> io::Result<()> {
// TODO: implement this, flush as much as possible from buffer
self.inner.flush()
}
}
/// Something that can encrypt or decrypt given data using ECE.
pub struct EceCrypt {
mode: CryptMode,
seq: usize,
// TODO: remove this buffer, not needed anymore?
/// Input buffer.
buf: BytesMut,
}
impl EceCrypt {
pub fn new(mode: CryptMode, input_size: usize) -> Self {
Self {
mode,
seq: 0,
buf: BytesMut::with_capacity(input_size),
}
}
}
impl Crypt for EceCrypt {
type Reader = EceReader;
type Writer = EceWriter;
fn crypt(&mut self, input: &[u8]) -> (usize, Option<Vec<u8>>) {
// How much to read, based on capacity that is left and given bytes
let size = cmp::min(self.buf.capacity() - self.buf.len(), input.len());
// Read bytes into the buffer
self.buf.put(&input[0..size]);
// TODO: encrypt/decrypt bytes, produce the result
panic!("not yet implemented");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment