parent
89f706d07d
commit
dbfcaafdb0
@ -0,0 +1,175 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use super::*;
|
||||
use key::*;
|
||||
|
||||
use std::io::{self, Write};
|
||||
use std::fmt;
|
||||
use openssl::{
|
||||
symm::Crypter,
|
||||
error::ErrorStack,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
pub const BUFFER_SIZE: usize = 1024;
|
||||
pub type Error = ErrorStack;
|
||||
|
||||
/// ChaCha Sink
|
||||
//#[derive(Debug)]
|
||||
pub struct Sink<W>
|
||||
{
|
||||
stream: W,
|
||||
crypter: Crypter, // for chacha, finalize does nothing it seems. we can also call it multiple times.
|
||||
|
||||
buffer: SmallVec<[u8; BUFFER_SIZE]> // used to buffer the operation
|
||||
}
|
||||
|
||||
impl<W: fmt::Debug> fmt::Debug for Sink<W>
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||
{
|
||||
write!(f, "Sink({:?}, ({} buffer cap))", self.stream, self.buffer.capacity())
|
||||
}
|
||||
}
|
||||
|
||||
impl<W> Sink<W>
|
||||
where W: Write
|
||||
{
|
||||
/// Create a new Chacha Sink stream wrapper
|
||||
pub fn new(stream: W, crypter: Crypter) -> Self
|
||||
{
|
||||
Self{stream, crypter, buffer: SmallVec::new()}
|
||||
}
|
||||
|
||||
/// Create an encrypting Chacha Sink stream wrapper
|
||||
pub fn encrypt(stream: W, key: Key, iv: IV) -> Result<Self, Error>
|
||||
{
|
||||
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<Self, Error>
|
||||
{
|
||||
Ok(Self::new(stream, cha::decrypter(key, iv)?))
|
||||
}
|
||||
|
||||
/// Consume into the inner stream
|
||||
pub fn into_inner(self) -> W
|
||||
{
|
||||
self.stream
|
||||
}
|
||||
|
||||
/// Consume into the inner stream and crypter
|
||||
pub fn into_parts(self) -> (W, Crypter)
|
||||
{
|
||||
(self.stream, self.crypter)
|
||||
}
|
||||
|
||||
/// The crypter of this instance
|
||||
pub fn crypter(&self) -> &Crypter
|
||||
{
|
||||
&self.crypter
|
||||
}
|
||||
|
||||
/// The crypter of this instance
|
||||
pub fn crypter_mut(&mut self) -> &mut Crypter
|
||||
{
|
||||
&mut self.crypter
|
||||
}
|
||||
|
||||
/// The inner stream
|
||||
pub fn inner(&self) -> &W
|
||||
{
|
||||
&self.stream
|
||||
}
|
||||
|
||||
/// The inner stream
|
||||
pub fn inner_mut(&mut self) -> &mut W
|
||||
{
|
||||
&mut self.stream
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Write> Write for Sink<W>
|
||||
{
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
prog1!{
|
||||
{
|
||||
self.buffer.write_all(buf).unwrap();
|
||||
let n = self.crypter.update(&buf[..], &mut self.buffer[..])?;
|
||||
self.crypter.finalize(&mut self.buffer[..n])?; // I don't think this is needed
|
||||
|
||||
self.stream.write(&self.buffer[..n])
|
||||
},
|
||||
self.buffer.clear();
|
||||
}
|
||||
}
|
||||
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
|
||||
prog1!{
|
||||
{
|
||||
self.buffer.write_all(buf).unwrap();
|
||||
let n = self.crypter.update(&buf[..], &mut self.buffer[..])?;
|
||||
self.crypter.finalize(&mut self.buffer[..n])?;
|
||||
|
||||
self.stream.write_all(&self.buffer[..n])
|
||||
},
|
||||
self.buffer.clear();
|
||||
}
|
||||
}
|
||||
#[inline] fn flush(&mut self) -> io::Result<()> {
|
||||
self.stream.flush()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests
|
||||
{
|
||||
use super::*;
|
||||
|
||||
const INPUT: &'static str = "Hello world!";
|
||||
|
||||
fn enc_stream(input: impl AsRef<[u8]>, key: Key, iv: IV) -> Sink<Vec<u8>>
|
||||
{
|
||||
let enc_buffer = Vec::new();
|
||||
let input = input.as_ref();
|
||||
|
||||
eprintln!("(enc) Key: {}, IV: {}, Input: ({}, {})", key, iv, input.len(), input.hex());
|
||||
|
||||
let mut stream = Sink::encrypt(enc_buffer, key, iv).expect("sink::enc");
|
||||
assert_eq!(stream.write(input).unwrap(), input.len());
|
||||
stream.flush().unwrap();
|
||||
|
||||
eprintln!("Output encrypted: {}", stream.inner().hex());
|
||||
|
||||
stream
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enc()
|
||||
{
|
||||
let (key, iv) = cha::keygen();
|
||||
|
||||
eprintln!("Sink ends: {:?}", enc_stream(INPUT.as_bytes(), key, iv));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dec()
|
||||
{
|
||||
let (key, iv) = cha::keygen();
|
||||
eprintln!("Input unencrypted: {}", INPUT.hex());
|
||||
|
||||
let input = enc_stream(INPUT.as_bytes(), key.clone(), iv.clone()).into_inner();
|
||||
|
||||
let mut dec_buffer = Vec::new();
|
||||
{
|
||||
let mut stream = Sink::decrypt(&mut dec_buffer, key, iv).expect("sink::dec");
|
||||
|
||||
stream.write_all(&input[..]).unwrap();
|
||||
stream.flush().unwrap();
|
||||
|
||||
eprintln!("Output decrypted: {}", stream.inner().hex());
|
||||
}
|
||||
assert_eq!(&dec_buffer[..], INPUT.as_bytes());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in new issue