#![allow(unused)]
use crate::bufread;
use crate::read::Decryptor as ReadDecryptor;
use crate::read::Encryptor as ReadEncryptor;
use crate::write::Encryptor as WriteEncryptor;
use openssl::symm::{Cipher, Crypter, Mode};
use rand::Fill;
use size::Size;
use std::cmp::Ordering;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::io::BufWriter;
use std::io::SeekFrom;
use std::io::{BufReader, Read};
use std::path::Path;
use std::time::Instant;
fn create_rand_file(path: &Path, size: usize) {
let mut buffer = [0u8; 1024];
let mut remainder = size as usize;
let mut rng = rand::rng();
let mut dst = File::options()
.create(true)
.write(true)
.truncate(true)
.open(&path)
.unwrap();
while remainder > 0 {
buffer.fill(&mut rng);
let write_count = remainder.min(buffer.len());
dst.write_all(&buffer[..write_count]).unwrap();
remainder = remainder.checked_sub(write_count).unwrap();
}
}
struct OnDrop<F>
where
F: Fn(),
{
callback: F,
}
impl<F> OnDrop<F>
where
F: Fn(),
{
pub fn new(f: F) -> Self {
Self { callback: f }
}
}
impl<F> Drop for OnDrop<F>
where
F: Fn(),
{
fn drop(&mut self) {
(self.callback)()
}
}
#[test]
fn large_buffer_encrypt_decrypt() {
let cleanup = OnDrop::new(|| {
for f in ["issue_9.src", "issue_9.enc", "issue_9.dec"] {
let _ = std::fs::remove_file(Path::new(f));
}
});
let start = Instant::now();
let src_path = Path::new("issue_9.src");
let size = Size::from_mib(10);
create_rand_file(&src_path, size.bytes() as usize);
eprintln!("{} source file generated in {:?}", size, start.elapsed());
let mut rng = rand::rng();
let mut key = [0u8; 16];
key.fill(&mut rng);
let mut iv = [0u8; 16];
iv.fill(&mut rng);
let start = Instant::now();
let mut src = File::open(&src_path).unwrap();
let enc_path = Path::new("issue_9.enc");
let mut enc = File::options()
.write(true)
.truncate(true)
.create(true)
.open(&enc_path)
.unwrap();
let mut encryptor = WriteEncryptor::new(enc, Cipher::aes_128_cbc(), &key, &iv).unwrap();
let mut buffer = [0u8; 4096];
loop {
let read = src.read(&mut buffer).unwrap();
encryptor.write_all(&buffer[..read]).unwrap();
if read == 0 {
break;
}
}
encryptor.finish().unwrap();
eprintln!("File encrypted in {:?}", start.elapsed());
let start = Instant::now();
let dec_path = Path::new("issue_9.dec");
let mut dec = File::options()
.write(true)
.truncate(true)
.create(true)
.open(&dec_path)
.unwrap();
let mut dec = BufWriter::new(dec);
let mut enc = File::open(&enc_path).unwrap();
let mut enc = BufReader::new(enc);
let mut decryptor =
crate::bufread::Decryptor::new(enc, Cipher::aes_128_cbc(), &key, &iv).unwrap();
loop {
let read = decryptor.read(&mut buffer).unwrap();
dec.write_all(&buffer[..read]).unwrap();
if read == 0 {
break;
}
}
dec.flush().unwrap();
eprintln!("File decrypted in {:?}", start.elapsed());
assert_files_are_equal(&src_path, &dec_path);
}
fn assert_files_are_equal(lhs: &Path, rhs: &Path) {
let lhs_len = std::fs::metadata(&lhs).unwrap().len();
let rhs_len = std::fs::metadata(&rhs).unwrap().len();
assert_eq!(lhs_len, rhs_len, "Mismatch in file lengths!");
let mut file1 = File::open(&lhs).unwrap();
let mut file2 = File::open(&rhs).unwrap();
let mut buff1 = [0u8; 4096];
let mut buff2 = [0u8; 4096];
let mut chunk_start = 0;
loop {
let read = file1.read(&mut buff1).unwrap();
if read == 0 {
break;
}
file2.read_exact(&mut buff2[..read]).unwrap();
if buff1[..read].cmp(&buff2[..read]) != Ordering::Equal {
for i in 0..read {
if buff1[i] != buff2[i] {
panic!(
"Mismatch in file contents starting at {:x}",
chunk_start + i
);
}
}
}
chunk_start += read;
}
}