commit
c0d7234b5a
@ -0,0 +1,2 @@
|
|||||||
|
/target
|
||||||
|
Cargo.lock
|
@ -0,0 +1,19 @@
|
|||||||
|
[package]
|
||||||
|
name = "chacha20stream"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Avril <flanchan@cumallover.me>"]
|
||||||
|
edition = "2018"
|
||||||
|
license = "MIT"
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["smallvec"]
|
||||||
|
|
||||||
|
# Explicitly clear in-memory buffers with `explicit_bzero()` instead of normal `bzero()`.
|
||||||
|
explicit_clear = []
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
base64 = "0.13"
|
||||||
|
getrandom = "0.2"
|
||||||
|
openssl = "0.10"
|
||||||
|
smallvec = {version = "1.6", features=["union"], optional = true}
|
@ -0,0 +1,38 @@
|
|||||||
|
|
||||||
|
use openssl::{
|
||||||
|
symm::{
|
||||||
|
Cipher, Crypter, Mode,
|
||||||
|
},
|
||||||
|
error::ErrorStack,
|
||||||
|
};
|
||||||
|
use crate::key::{Key, IV};
|
||||||
|
|
||||||
|
pub const KEY_SIZE: usize = 32;
|
||||||
|
pub const IV_SIZE: usize = 12;
|
||||||
|
|
||||||
|
static NEW_CIPHER: fn() -> Cipher = Cipher::chacha20_poly1305;
|
||||||
|
|
||||||
|
#[inline] pub fn decrypter(key: impl AsRef<Key>, iv: impl AsRef<IV>) -> Result<Crypter, ErrorStack>
|
||||||
|
{
|
||||||
|
Crypter::new(
|
||||||
|
NEW_CIPHER(),
|
||||||
|
Mode::Decrypt,
|
||||||
|
key.as_ref().as_ref(),
|
||||||
|
Some(iv.as_ref().as_ref())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
#[inline] pub fn encrypter(key: impl AsRef<Key>, iv: impl AsRef<IV>) -> Result<Crypter, ErrorStack>
|
||||||
|
{
|
||||||
|
Crypter::new(
|
||||||
|
NEW_CIPHER(),
|
||||||
|
Mode::Encrypt,
|
||||||
|
key.as_ref().as_ref(),
|
||||||
|
Some(iv.as_ref().as_ref())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a random key and IV.
|
||||||
|
#[inline(always)] pub fn keygen() -> (Key, IV)
|
||||||
|
{
|
||||||
|
(Key::new(), IV::new())
|
||||||
|
}
|
@ -0,0 +1,122 @@
|
|||||||
|
use std::{
|
||||||
|
mem,
|
||||||
|
iter::{
|
||||||
|
self,
|
||||||
|
ExactSizeIterator,
|
||||||
|
FusedIterator,
|
||||||
|
},
|
||||||
|
slice,
|
||||||
|
fmt,
|
||||||
|
};
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct HexStringIter<I>(I, [u8; 2]);
|
||||||
|
|
||||||
|
impl<I: Iterator<Item = u8>> HexStringIter<I>
|
||||||
|
{
|
||||||
|
/// Write this hex string iterator to a formattable buffer
|
||||||
|
pub fn consume<F>(self, f: &mut F) -> fmt::Result
|
||||||
|
where F: std::fmt::Write
|
||||||
|
{
|
||||||
|
if self.1[0] != 0 {
|
||||||
|
write!(f, "{}", self.1[0] as char)?;
|
||||||
|
}
|
||||||
|
if self.1[1] != 0 {
|
||||||
|
write!(f, "{}", self.1[1] as char)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
for x in self.0 {
|
||||||
|
write!(f, "{:02x}", x)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consume into a string
|
||||||
|
pub fn into_string(self) -> String
|
||||||
|
{
|
||||||
|
let mut output = match self.size_hint() {
|
||||||
|
(0, None) => String::new(),
|
||||||
|
(_, Some(x)) |
|
||||||
|
(x, None) => String::with_capacity(x),
|
||||||
|
};
|
||||||
|
self.consume(&mut output).unwrap();
|
||||||
|
output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait HexStringIterExt<I>: Sized
|
||||||
|
{
|
||||||
|
fn into_hex(self) -> HexStringIter<I>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type HexStringSliceIter<'a> = HexStringIter<iter::Copied<slice::Iter<'a, u8>>>;
|
||||||
|
|
||||||
|
pub trait HexStringSliceIterExt
|
||||||
|
{
|
||||||
|
fn hex(&self) -> HexStringSliceIter<'_>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> HexStringSliceIterExt for S
|
||||||
|
where S: AsRef<[u8]>
|
||||||
|
{
|
||||||
|
fn hex(&self) -> HexStringSliceIter<'_>
|
||||||
|
{
|
||||||
|
self.as_ref().iter().copied().into_hex()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: IntoIterator<Item=u8>> HexStringIterExt<I::IntoIter> for I
|
||||||
|
{
|
||||||
|
#[inline] fn into_hex(self) -> HexStringIter<I::IntoIter> {
|
||||||
|
HexStringIter(self.into_iter(), [0u8; 2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Iterator<Item = u8>> Iterator for HexStringIter<I>
|
||||||
|
{
|
||||||
|
type Item = char;
|
||||||
|
fn next(&mut self) -> Option<Self::Item>
|
||||||
|
{
|
||||||
|
match self.1 {
|
||||||
|
[_, 0] => {
|
||||||
|
use std::io::Write;
|
||||||
|
write!(&mut self.1[..], "{:02x}", self.0.next()?).unwrap();
|
||||||
|
|
||||||
|
Some(mem::replace(&mut self.1[0], 0) as char)
|
||||||
|
},
|
||||||
|
[0, _] => Some(mem::replace(&mut self.1[1], 0) as char),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
let (l, h) = self.0.size_hint();
|
||||||
|
|
||||||
|
(l * 2, h.map(|x| x*2))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Iterator<Item = u8> + ExactSizeIterator> ExactSizeIterator for HexStringIter<I>{}
|
||||||
|
impl<I: Iterator<Item = u8> + FusedIterator> FusedIterator for HexStringIter<I>{}
|
||||||
|
|
||||||
|
impl<I: Iterator<Item = u8>> From<HexStringIter<I>> for String
|
||||||
|
{
|
||||||
|
fn from(from: HexStringIter<I>) -> Self
|
||||||
|
{
|
||||||
|
from.into_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Iterator<Item = u8> + Clone> fmt::Display for HexStringIter<I>
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
self.clone().consume(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export] macro_rules! prog1 {
|
||||||
|
($first:expr, $($rest:expr);+ $(;)?) => {
|
||||||
|
($first, $( $rest ),+).0
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,153 @@
|
|||||||
|
use getrandom::getrandom;
|
||||||
|
use std::{fmt, str};
|
||||||
|
pub use crate::cha::{
|
||||||
|
KEY_SIZE,
|
||||||
|
IV_SIZE,
|
||||||
|
};
|
||||||
|
use crate::ext::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy, Default)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct Key([u8; KEY_SIZE]);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy, Default)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct IV([u8; IV_SIZE]);
|
||||||
|
|
||||||
|
impl Key
|
||||||
|
{
|
||||||
|
#[inline] pub fn from_bytes(k: [u8; KEY_SIZE]) -> Self
|
||||||
|
{
|
||||||
|
Self(k)
|
||||||
|
}
|
||||||
|
pub fn new() -> Self
|
||||||
|
{
|
||||||
|
let mut output = [0u8; KEY_SIZE];
|
||||||
|
getrandom(&mut output[..]).expect("rng fatal");
|
||||||
|
Self(output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IV
|
||||||
|
{
|
||||||
|
|
||||||
|
#[inline] pub fn from_bytes(k: [u8; IV_SIZE]) -> Self
|
||||||
|
{
|
||||||
|
Self(k)
|
||||||
|
}
|
||||||
|
pub fn new() -> Self
|
||||||
|
{
|
||||||
|
let mut output = [0u8; IV_SIZE];
|
||||||
|
getrandom(&mut output[..]).expect("rng fatal");
|
||||||
|
Self(output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<[u8; KEY_SIZE]> for Key
|
||||||
|
{
|
||||||
|
#[inline] fn from(from: [u8; KEY_SIZE]) -> Self
|
||||||
|
{
|
||||||
|
Self(from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<[u8; IV_SIZE]> for IV
|
||||||
|
{
|
||||||
|
fn from(from: [u8; IV_SIZE]) -> Self
|
||||||
|
{
|
||||||
|
Self(from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl AsRef<[u8]> for Key
|
||||||
|
{
|
||||||
|
fn as_ref(&self) -> &[u8]
|
||||||
|
{
|
||||||
|
&self.0[..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl AsRef<[u8]> for IV
|
||||||
|
{
|
||||||
|
fn as_ref(&self) -> &[u8]
|
||||||
|
{
|
||||||
|
&self.0[..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsMut<[u8]> for Key
|
||||||
|
{
|
||||||
|
fn as_mut(&mut self) -> &mut [u8]
|
||||||
|
{
|
||||||
|
&mut self.0[..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsMut<[u8]> for IV
|
||||||
|
{
|
||||||
|
fn as_mut(&mut self) -> &mut [u8]
|
||||||
|
{
|
||||||
|
&mut self.0[..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<Key> for Key
|
||||||
|
{
|
||||||
|
#[inline] fn as_ref(&self) -> &Key
|
||||||
|
{
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl AsRef<IV> for IV
|
||||||
|
{
|
||||||
|
#[inline] fn as_ref(&self) -> &IV
|
||||||
|
{
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Key
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
write!(f, "{}", self.0.iter().copied().into_hex())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for IV
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
write!(f, "{}", self.0.iter().copied().into_hex())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl str::FromStr for Key
|
||||||
|
{
|
||||||
|
type Err = base64::DecodeError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let mut buffer = Vec::with_capacity(KEY_SIZE);
|
||||||
|
base64::decode_config_buf(s.as_bytes(), base64::STANDARD, &mut buffer)?;
|
||||||
|
|
||||||
|
let mut this = Self::default();
|
||||||
|
let sz = std::cmp::min(KEY_SIZE, buffer.len());
|
||||||
|
(&mut this.0[..sz]).copy_from_slice(&buffer[..sz]);
|
||||||
|
Ok(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl str::FromStr for IV
|
||||||
|
{
|
||||||
|
type Err = base64::DecodeError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let mut buffer = Vec::with_capacity(IV_SIZE);
|
||||||
|
base64::decode_config_buf(s.as_bytes(), base64::STANDARD, &mut buffer)?;
|
||||||
|
|
||||||
|
let mut this = Self::default();
|
||||||
|
let sz = std::cmp::min(IV_SIZE, buffer.len());
|
||||||
|
(&mut this.0[..sz]).copy_from_slice(&buffer[..sz]);
|
||||||
|
Ok(this)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
//extern crate test;
|
||||||
|
|
||||||
|
#[macro_use] mod ext; #[allow(unused_imports)] use ext::*;
|
||||||
|
|
||||||
|
pub mod key;
|
||||||
|
mod cha;
|
||||||
|
mod stream;
|
||||||
|
|
||||||
|
pub use stream::Sink;
|
||||||
|
pub use key::{
|
||||||
|
Key, IV,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use cha::keygen;
|
@ -0,0 +1,250 @@
|
|||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use key::*;
|
||||||
|
|
||||||
|
use std::io::{self, Write};
|
||||||
|
use std::fmt;
|
||||||
|
use openssl::{
|
||||||
|
symm::Crypter,
|
||||||
|
error::ErrorStack,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(feature="smallvec")]
|
||||||
|
pub const BUFFER_SIZE: usize = 32;
|
||||||
|
|
||||||
|
#[cfg(feature="smallvec")]
|
||||||
|
type BufferVec = smallvec::SmallVec<[u8; BUFFER_SIZE]>;
|
||||||
|
#[cfg(not(feature="smallvec"))]
|
||||||
|
type BufferVec = Vec<u8>;
|
||||||
|
|
||||||
|
pub type Error = ErrorStack;
|
||||||
|
|
||||||
|
/// ChaCha Sink
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
/// When writing, a temporary buffer stored in the structure is used. This buffer is **not** cleared after a write, for efficiency reasons. This may leave sensitive information in the buffer after the write operation.
|
||||||
|
/// The `flush()` implementation *does* clear this buffer.
|
||||||
|
/// You can use the `prune()` function to zero out this buffer manually too.
|
||||||
|
//#[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: BufferVec, // 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
|
||||||
|
#[inline] fn new(stream: W, crypter: Crypter) -> Self
|
||||||
|
{
|
||||||
|
Self{stream, crypter, buffer: BufferVec::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
|
||||||
|
#[inline] pub fn into_inner(self) -> W
|
||||||
|
{
|
||||||
|
self.stream
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consume into the inner stream and crypter
|
||||||
|
#[inline] pub fn into_parts(self) -> (W, Crypter)
|
||||||
|
{
|
||||||
|
(self.stream, self.crypter)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The crypter of this instance
|
||||||
|
#[inline] pub fn crypter(&self) -> &Crypter
|
||||||
|
{
|
||||||
|
&self.crypter
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The crypter of this instance
|
||||||
|
#[inline] pub fn crypter_mut(&mut self) -> &mut Crypter
|
||||||
|
{
|
||||||
|
&mut self.crypter
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The inner stream
|
||||||
|
#[inline] pub fn inner(&self) -> &W
|
||||||
|
{
|
||||||
|
&self.stream
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The inner stream
|
||||||
|
#[inline] pub fn inner_mut(&mut self) -> &mut W
|
||||||
|
{
|
||||||
|
&mut self.stream
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Perform the cipher transform on this input to the inner buffer, returning the number of bytes updated.
|
||||||
|
fn transform(&mut self, buf: &[u8]) -> Result<usize, ErrorStack>
|
||||||
|
{
|
||||||
|
if buf.len() > self.buffer.len() {
|
||||||
|
self.buffer.resize(buf.len(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let n = self.crypter.update(&buf[..], &mut self.buffer[..])?;
|
||||||
|
let _f = self.crypter.finalize(&mut self.buffer[..n])?; // I don't know if this is needed.
|
||||||
|
debug_assert_eq!(_f, 0);
|
||||||
|
|
||||||
|
Ok(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear the internal buffer while keeping it allocated for further use.
|
||||||
|
///
|
||||||
|
/// This does not affect operations at all, all it does is 0 out the left-over temporary buffer from the last operation(s).
|
||||||
|
pub fn prune(&mut self)
|
||||||
|
{
|
||||||
|
#[cfg(feature="explicit_clear")]
|
||||||
|
{
|
||||||
|
use std::ffi::c_void;
|
||||||
|
extern "C" {
|
||||||
|
fn explicit_bzero(_: *mut c_void, _:usize);
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
explicit_bzero(self.buffer.as_mut_ptr() as *mut c_void, self.buffer.len());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#[cfg(not(feature="explicit_clear"))]
|
||||||
|
unsafe {
|
||||||
|
std::ptr::write_bytes(self.buffer.as_mut_ptr(), 0, self.buffer.len());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: Write> Write for Sink<W>
|
||||||
|
{
|
||||||
|
#[inline] fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||||
|
let n = self.transform(buf)?;
|
||||||
|
|
||||||
|
self.stream.write(&self.buffer[..n])
|
||||||
|
|
||||||
|
}
|
||||||
|
#[inline] fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
|
||||||
|
let n = self.transform(buf)?;
|
||||||
|
|
||||||
|
self.stream.write_all(&self.buffer[..n])
|
||||||
|
}
|
||||||
|
#[inline] fn flush(&mut self) -> io::Result<()> {
|
||||||
|
#[cfg(feature="explicit_clear")] self.prune();
|
||||||
|
self.buffer.clear();
|
||||||
|
|
||||||
|
self.stream.flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests
|
||||||
|
{
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const INPUT: &'static str = "Hello world!Hello world!Hello world!Hello world!Hello world!Hello world!Hello world!Hello world!Hello world!Hello world!Hello world!Hello world!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()
|
||||||
|
{
|
||||||
|
println!(">>> Sink's size with ref is {}", std::mem::size_of::<Sink<&mut Vec<u8>>>());
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if explicit clear is actually clearing.
|
||||||
|
#[cfg(feature="explicit_clear")]
|
||||||
|
#[test]
|
||||||
|
fn remainder()
|
||||||
|
{
|
||||||
|
let mut dec_buffer = Vec::new();
|
||||||
|
|
||||||
|
let (buf, off, _s) = {
|
||||||
|
let (key, iv) = cha::keygen();
|
||||||
|
|
||||||
|
let input = enc_stream(INPUT.as_bytes(), key.clone(), iv.clone()).into_inner();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut stream = Sink::decrypt(&mut dec_buffer, key, iv).expect("sink::rem");
|
||||||
|
|
||||||
|
stream.write_all(&input[..]).unwrap();
|
||||||
|
|
||||||
|
let by = stream.buffer[0];
|
||||||
|
//stream.prune();
|
||||||
|
stream.flush().unwrap();
|
||||||
|
(by, (stream.buffer.as_ptr() as u64), stream)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check to see if the buffer remains in our process's memory.
|
||||||
|
use std::fs::OpenOptions;
|
||||||
|
use std::io::{Seek, SeekFrom, Read};
|
||||||
|
let mut file = OpenOptions::new().read(true).open("/proc/self/mem").unwrap();
|
||||||
|
|
||||||
|
file.seek(SeekFrom::Start(off)).unwrap();
|
||||||
|
let mut chk = [0u8; 10];
|
||||||
|
file.read_exact(&mut chk).unwrap();
|
||||||
|
assert!(buf != chk[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in new issue