diff --git a/Cargo.lock b/Cargo.lock index 8d2d0a9e..5253f5bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1330,6 +1330,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "lz4_flex" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373f5eceeeab7925e0c1098212f2fbc4d416adec9d35051a6ab251e824c1854a" +dependencies = [ + "twox-hash", +] + [[package]] name = "matchers" version = "0.1.0" @@ -1865,6 +1874,7 @@ dependencies = [ "keyring", "libc", "lru", + "lz4_flex", "num-format", "okaywal", "rand", @@ -2523,6 +2533,12 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "twox-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" + [[package]] name = "typenum" version = "1.17.0" diff --git a/Cargo.toml b/Cargo.toml index 8484ba24..98176870 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ documentation = "https://docs.rs/rencfs" exclude = [".github/"] [dependencies] +lz4_flex = "0.11" clap = { version = "4.5.4", features = ["derive", "cargo"] } libc = "0.2.153" serde = { version = "1.0.197", features = ["derive"] } diff --git a/benches/crypto_read.rs b/benches/crypto_read.rs index edb326c3..b3b09536 100644 --- a/benches/crypto_read.rs +++ b/benches/crypto_read.rs @@ -16,7 +16,7 @@ fn bench_read_1mb_chacha_file(c: &mut Criterion) { let key = SecretVec::new(Box::new(key)); let file = tempfile::tempfile().unwrap(); - let mut writer = crypto::create_write(file, cipher, &key); + let mut writer = crypto::create_write(file, cipher, &key, false); let mut cursor_random = io::Cursor::new(vec![0; len]); rand::thread_rng().fill_bytes(cursor_random.get_mut()); cursor_random.seek(io::SeekFrom::Start(0)).unwrap(); @@ -27,7 +27,7 @@ fn bench_read_1mb_chacha_file(c: &mut Criterion) { b.iter(|| { let mut file = file.try_clone().unwrap(); file.seek(io::SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(file, cipher, &key); + let mut reader = crypto::create_read(file, cipher, &key, false); black_box(&reader); io::copy(&mut reader, &mut io::sink()).unwrap(); }); @@ -45,7 +45,7 @@ fn bench_read_1mb_aes_file(c: &mut Criterion) { c.bench_function("bench_read_1mb_aes_file", |b| { b.iter(|| { let file = tempfile::tempfile().unwrap(); - let mut writer = crypto::create_write(file, cipher, &key); + let mut writer = crypto::create_write(file, cipher, &key, false); let mut cursor_random = io::Cursor::new(vec![0; len]); rand::thread_rng().fill_bytes(cursor_random.get_mut()); cursor_random.seek(io::SeekFrom::Start(0)).unwrap(); @@ -65,7 +65,7 @@ fn bench_read_1mb_chacha_ram(c: &mut Criterion) { let key = SecretVec::new(Box::new(key)); let cursor_write = io::Cursor::new(vec![]); - let mut writer = crypto::create_write(cursor_write, cipher, &key); + let mut writer = crypto::create_write(cursor_write, cipher, &key, false); let mut cursor_random = io::Cursor::new(vec![0; len]); rand::thread_rng().fill_bytes(cursor_random.get_mut()); cursor_random.seek(io::SeekFrom::Start(0)).unwrap(); @@ -76,7 +76,7 @@ fn bench_read_1mb_chacha_ram(c: &mut Criterion) { b.iter(|| { let mut cursor = cursor_write.clone(); cursor.seek(io::SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(cursor, cipher, &key); + let mut reader = crypto::create_read(cursor, cipher, &key, false); black_box(&reader); io::copy(&mut reader, &mut io::sink()).unwrap(); }); @@ -92,7 +92,7 @@ fn bench_read_1mb_aes_ram(c: &mut Criterion) { let key = SecretVec::new(Box::new(key)); let cursor_write = io::Cursor::new(vec![]); - let mut writer = crypto::create_write(cursor_write, cipher, &key); + let mut writer = crypto::create_write(cursor_write, cipher, &key, false); let mut cursor_random = io::Cursor::new(vec![0; len]); rand::thread_rng().fill_bytes(cursor_random.get_mut()); cursor_random.seek(io::SeekFrom::Start(0)).unwrap(); @@ -103,7 +103,7 @@ fn bench_read_1mb_aes_ram(c: &mut Criterion) { b.iter(|| { let mut cursor = cursor_write.clone(); cursor.seek(io::SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(cursor, cipher, &key); + let mut reader = crypto::create_read(cursor, cipher, &key, false); black_box(&reader); io::copy(&mut reader, &mut io::sink()).unwrap(); }); diff --git a/examples/crypto_speed.rs b/examples/crypto_speed.rs index f9e8cfb4..2a080bc7 100644 --- a/examples/crypto_speed.rs +++ b/examples/crypto_speed.rs @@ -86,9 +86,9 @@ fn stream_speed( let path_out2 = Path::new(&path_out).to_path_buf().with_extension("dec"); let _ = fs::remove_file(path_out2.clone()); let mut file_out2 = File::create(path_out2.clone())?; - let mut writer = crypto::create_write(file_out, cipher, key); + let mut writer = crypto::create_write(file_out, cipher, key, true); let size = file_in.metadata()?.len(); - let f = || crypto::create_read(File::open(path_out).unwrap(), cipher, key); + let f = || crypto::create_read(File::open(path_out).unwrap(), cipher, key, false); test_speed(&mut file_in, &mut writer, &mut file_out2, size, f)?; file_in.seek(io::SeekFrom::Start(0))?; check_hash(&mut file_in, &mut f())?; @@ -101,12 +101,12 @@ fn file_speed(path_in: &str, path_out: &str, cipher: Cipher, key: &SecretVec println!("file speed"); let _ = fs::remove_file(path_out); let mut file_in = File::open(path_in)?; - let mut writer = crypto::create_write(File::create(Path::new(path_out))?, cipher, key); + let mut writer = crypto::create_write(File::create(Path::new(path_out))?, cipher, key, true); let path_out2 = Path::new(&path_out).to_path_buf().with_extension("dec"); let _ = fs::remove_file(path_out2.clone()); let mut file_out2 = File::create(path_out2.clone())?; let size = file_in.metadata()?.len(); - let f = || crypto::create_read(File::open(path_out).unwrap(), cipher, key); + let f = || crypto::create_read(File::open(path_out).unwrap(), cipher, key, false); test_speed(&mut file_in, &mut writer, &mut file_out2, size, f)?; file_in.seek(io::SeekFrom::Start(0)).unwrap(); check_hash(&mut file_in, &mut f())?; diff --git a/examples/crypto_write_read.rs b/examples/crypto_write_read.rs index 32181f8a..e966f1d6 100644 --- a/examples/crypto_write_read.rs +++ b/examples/crypto_write_read.rs @@ -32,12 +32,12 @@ fn main() -> Result<()> { } let mut file = File::open(path_in.clone())?; - let mut writer = crypto::create_write(File::create(out.clone())?, cipher, &key); + let mut writer = crypto::create_write(File::create(out.clone())?, cipher, &key, true); info!("encrypt file"); io::copy(&mut file, &mut writer).unwrap(); writer.finish()?; - let mut reader = crypto::create_read(File::open(out)?, cipher, &key); + let mut reader = crypto::create_read(File::open(out)?, cipher, &key, false); info!("read file and compare hash to original one"); let hash1 = crypto::hash_reader(&mut File::open(path_in)?)?; let hash2 = crypto::hash_reader(&mut reader)?; diff --git a/examples/internal_ring_speed.rs b/examples/internal_ring_speed.rs index d1cbb4fa..06605f12 100644 --- a/examples/internal_ring_speed.rs +++ b/examples/internal_ring_speed.rs @@ -80,14 +80,12 @@ fn main() -> io::Result<()> { let len = { let mut pos = 0; loop { - match input.read(&mut buffer[pos..]) { - Ok(read) => { - pos += read; - if read == 0 { - break; - } + { + let read = input.read(&mut buffer[pos..])?; + pos += read; + if read == 0 { + break; } - Err(err) => return Err(err), } } pos @@ -139,14 +137,12 @@ fn main() -> io::Result<()> { let len = { let mut pos = 0; loop { - match input.read(&mut buffer[pos..]) { - Ok(read) => { - pos += read; - if read == 0 { - break; - } + { + let read = input.read(&mut buffer[pos..])?; + pos += read; + if read == 0 { + break; } - Err(err) => return Err(err), } } pos diff --git a/src/crypto.rs b/src/crypto.rs index 72ca489a..1f546eb5 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -19,7 +19,7 @@ use serde::{Deserialize, Serialize}; use shush_rs::{ExposeSecret, SecretString, SecretVec}; use strum_macros::{Display, EnumIter, EnumString}; use thiserror::Error; -use tracing::{debug, error, instrument}; +use tracing::{debug, instrument}; use write::CryptoInnerWriter; use crate::crypto::read::{CryptoRead, CryptoReadSeek, RingCryptoRead}; @@ -114,8 +114,9 @@ pub fn create_write( writer: W, cipher: Cipher, key: &SecretVec, + is_compressed: bool, ) -> impl CryptoWrite { - create_ring_write(writer, cipher, key) + create_ring_write(writer, cipher, key, is_compressed) } /// Creates an encrypted writer with seek @@ -123,56 +124,61 @@ pub fn create_write_seek, + is_compressed: bool, ) -> impl CryptoWriteSeek { - create_ring_write_seek(writer, cipher, key) + create_ring_write_seek(writer, cipher, key, is_compressed) } fn create_ring_write( writer: W, cipher: Cipher, key: &SecretVec, + is_compressed: bool, ) -> RingCryptoWrite { let algorithm = match cipher { Cipher::ChaCha20Poly1305 => &CHACHA20_POLY1305, Cipher::Aes256Gcm => &AES_256_GCM, }; - RingCryptoWrite::new(writer, false, algorithm, key) + RingCryptoWrite::new(writer, false, algorithm, key, is_compressed) } fn create_ring_write_seek( writer: W, cipher: Cipher, key: &SecretVec, + is_compressed: bool, ) -> RingCryptoWrite { let algorithm = match cipher { Cipher::ChaCha20Poly1305 => &CHACHA20_POLY1305, Cipher::Aes256Gcm => &AES_256_GCM, }; - RingCryptoWrite::new(writer, true, algorithm, key) + RingCryptoWrite::new(writer, true, algorithm, key, is_compressed) } fn create_ring_read( reader: R, cipher: Cipher, key: &SecretVec, + is_compressed: bool, ) -> RingCryptoRead { let algorithm = match cipher { Cipher::ChaCha20Poly1305 => &CHACHA20_POLY1305, Cipher::Aes256Gcm => &AES_256_GCM, }; - RingCryptoRead::new(reader, algorithm, key) + RingCryptoRead::new(reader, algorithm, key, is_compressed) } fn create_ring_read_seek( reader: R, cipher: Cipher, key: &SecretVec, + is_compressed: bool, ) -> RingCryptoRead { let algorithm = match cipher { Cipher::ChaCha20Poly1305 => &CHACHA20_POLY1305, Cipher::Aes256Gcm => &AES_256_GCM, }; - RingCryptoRead::new_seek(reader, algorithm, key) + RingCryptoRead::new_seek(reader, algorithm, key, is_compressed) } /// Creates an encrypted reader @@ -180,8 +186,9 @@ pub fn create_read( reader: R, cipher: Cipher, key: &SecretVec, + is_compressed: bool, ) -> impl CryptoRead { - create_ring_read(reader, cipher, key) + create_ring_read(reader, cipher, key, is_compressed) } /// Creates an encrypted reader with seek @@ -189,14 +196,15 @@ pub fn create_read_seek( reader: R, cipher: Cipher, key: &SecretVec, + is_compressed: bool, ) -> impl CryptoReadSeek { - create_ring_read_seek(reader, cipher, key) + create_ring_read_seek(reader, cipher, key, is_compressed) } #[allow(clippy::missing_errors_doc)] pub fn encrypt(s: &SecretString, cipher: Cipher, key: &SecretVec) -> Result { let mut cursor = io::Cursor::new(vec![]); - let mut writer = create_write(cursor, cipher, key); + let mut writer = create_write(cursor, cipher, key, false); writer.write_all(s.expose_secret().as_bytes())?; cursor = writer.finish()?; let v = cursor.into_inner(); @@ -209,7 +217,7 @@ pub fn decrypt(s: &str, cipher: Cipher, key: &SecretVec) -> Result: Read + Send + Sync { /// ring #[macro_export] macro_rules! decrypt_block { - ($block_index:expr, $buf:expr, $input:expr, $last_nonce:expr, $opening_key:expr) => {{ + ($block_index:expr, $buf:expr, $input:expr, $last_nonce:expr, $opening_key:expr, $is_compressed:expr) => {{ let len = { $buf.clear(); let buffer = $buf.as_mut_remaining(); @@ -45,34 +45,68 @@ macro_rules! decrypt_block { pos }; if len != 0 { - let data = &mut buffer[..len]; - let aad = Aad::from(($block_index).to_le_bytes()); - // extract nonce + let mut data = &mut buffer[..len]; + $last_nonce .lock() .unwrap() .replace(data[..NONCE_LEN].to_vec()); - let data = &mut data[NONCE_LEN..]; - let plaintext = $opening_key.open_within(aad, data, 0..).map_err(|err| { - error!("error opening within: {}", err); - io::Error::other("error opening within") - })?; - len = plaintext.len(); + data = &mut data[NONCE_LEN..]; + + if $is_compressed { + // Extract the 4-byte length header + let mut len_bytes = [0u8; 4]; + len_bytes.copy_from_slice(&data[0..4]); + let comp_len = u32::from_le_bytes(len_bytes) as usize; + + // The payload is immediately after the 4-byte header + data = &mut data[4..]; + + // Slice out exactly the payload + tag, ignoring the padded zeros! + let target_len = comp_len + $opening_key.algorithm().tag_len(); + // Ensure we don't panic if the file was truncated unexpectedly + let target_len = target_len.min(data.len()); + let payload = &mut data[..target_len]; + + let mut aad_bytes = ($block_index).to_le_bytes().to_vec(); + aad_bytes.extend_from_slice(&(comp_len as u32).to_le_bytes()); + let aad = Aad::from(aad_bytes); + + let plaintext = $opening_key.open_within(aad, payload, 0..).map_err(|err| { + error!("error opening within: {}", err); + io::Error::other("error opening within") + })?; + + let decompressed = lz4_flex::decompress_size_prepended(plaintext) + .map_err(|e| io::Error::other(format!("lz4 decompress error: {}", e)))?; + + // Put decompressed data back into the main buffer for stream consumption + // We must write it starting AFTER the NONCE + let write_target = &mut buffer[NONCE_LEN..NONCE_LEN + decompressed.len()]; + write_target.copy_from_slice(&decompressed); + len = decompressed.len(); + } else { + let aad = Aad::from(($block_index).to_le_bytes()); + let plaintext = $opening_key.open_within(aad, data, 0..).map_err(|err| { + error!("error opening within: {}", err); + io::Error::other("error opening within") + })?; + // open_within decrypts in-place, so the data is already exactly + // where it needs to be (starting after the NONCE). + len = plaintext.len(); + } } len }; if len != 0 { $buf.seek_available(SeekFrom::Start(NONCE_LEN as u64 + len as u64)) .unwrap(); - // skip nonce $buf.seek_read(SeekFrom::Start(NONCE_LEN as u64)).unwrap(); $block_index += 1; } }}; } -pub(crate) use decrypt_block; - #[allow(clippy::module_name_repetitions)] pub struct RingCryptoRead { input: Option, @@ -82,12 +116,22 @@ pub struct RingCryptoRead { ciphertext_block_size: usize, plaintext_block_size: usize, block_index: u64, + pub is_compressed: bool, } impl RingCryptoRead { #[allow(clippy::missing_panics_doc)] - pub fn new(reader: R, algorithm: &'static Algorithm, key: &SecretVec) -> Self { - let ciphertext_block_size = NONCE_LEN + BLOCK_SIZE + algorithm.tag_len(); + pub fn new( + reader: R, + algorithm: &'static Algorithm, + key: &SecretVec, + is_compressed: bool, + ) -> Self { + let ciphertext_block_size = if is_compressed { + NONCE_LEN + 4 + BLOCK_SIZE + algorithm.tag_len() + } else { + NONCE_LEN + BLOCK_SIZE + algorithm.tag_len() + }; let buf = BufMut::new(vec![0; ciphertext_block_size]); let last_nonce = Arc::new(Mutex::new(None)); let unbound_key = UnboundKey::new(algorithm, &key.expose_secret()).unwrap(); @@ -101,6 +145,7 @@ impl RingCryptoRead { ciphertext_block_size, plaintext_block_size: BLOCK_SIZE, block_index: 0, + is_compressed, } } } @@ -119,7 +164,8 @@ impl Read for RingCryptoRead { self.buf, self.input.as_mut().unwrap(), self.last_nonce, - self.opening_key + self.opening_key, + self.is_compressed ); let len = self.buf.read(buf)?; Ok(len) @@ -155,8 +201,13 @@ pub trait CryptoReadSeek: } impl RingCryptoRead { - pub fn new_seek(reader: R, algorithm: &'static Algorithm, key: &SecretVec) -> Self { - Self::new(reader, algorithm, key) + pub fn new_seek( + reader: R, + algorithm: &'static Algorithm, + key: &SecretVec, + is_compressed: bool, + ) -> Self { + Self::new(reader, algorithm, key, is_compressed) } const fn pos(&self) -> u64 { @@ -201,7 +252,7 @@ impl Seek for RingCryptoRead { let block_index = self.pos() / self.plaintext_block_size as u64; let new_block_index = new_pos / self.plaintext_block_size as u64; if block_index == new_block_index { - let at_full_block_end = self.pos() % self.plaintext_block_size as u64 == 0 + let at_full_block_end = self.pos().is_multiple_of(self.plaintext_block_size as u64) && self.buf.available_read() == 0; if self.buf.available() > 0 // this make sure we are not at the end of the current block, which is the start boundary of next block @@ -224,7 +275,7 @@ impl Seek for RingCryptoRead { ))?; self.buf.clear(); self.block_index = new_block_index; - if new_pos % self.plaintext_block_size as u64 == 0 { + if new_pos.is_multiple_of(self.plaintext_block_size as u64) { // in case we need to seek at the start of the new block, we need to decrypt here, because we altered // the block_index but the seek seek_forward from below will not decrypt anything // as the offset in new block is 0. In that case the po() @@ -234,7 +285,8 @@ impl Seek for RingCryptoRead { self.buf, self.input.as_mut().unwrap(), self.last_nonce, - self.opening_key + self.opening_key, + self.is_compressed ); } // seek inside new block diff --git a/src/crypto/read/test.rs b/src/crypto/read/test.rs index 1c6ba587..6194054d 100644 --- a/src/crypto/read/test.rs +++ b/src/crypto/read/test.rs @@ -25,7 +25,7 @@ fn create_encrypted_data(data: &[u8], key: &SecretVec) -> Vec { let writer = Cursor::new(Vec::new()); let cipher = Cipher::ChaCha20Poly1305; - let mut crypto_writer = crypto::create_write(writer, cipher, key); + let mut crypto_writer = crypto::create_write(writer, cipher, key, false); crypto_writer.write_all(data).unwrap(); @@ -43,7 +43,7 @@ fn test_read_empty() { let mut buf = [0u8; 10]; let cipher = &CHACHA20_POLY1305; let key = create_secret_key(CHACHA20_POLY1305.key_len()); - let mut crypto_reader = RingCryptoRead::new(reader, cipher, &key); + let mut crypto_reader = RingCryptoRead::new(reader, cipher, &key, false); let result = &crypto_reader.read(&mut buf).unwrap(); let expected: usize = 0; assert_eq!(*result, expected); @@ -61,7 +61,8 @@ fn test_read_single_block() { let data = binding.as_bytes(); let key = create_secret_key(CHACHA20_POLY1305.key_len()); let encrypted_data = create_encrypted_data(data, &key); - let mut reader = RingCryptoRead::new(Cursor::new(encrypted_data), &CHACHA20_POLY1305, &key); + let mut reader = + RingCryptoRead::new(Cursor::new(encrypted_data), &CHACHA20_POLY1305, &key, false); let mut buf = vec![0u8; BLOCK_SIZE]; assert_eq!(reader.read(&mut buf).unwrap(), BLOCK_SIZE); } @@ -82,7 +83,8 @@ fn test_read_multiple_blocks() { let data = binding.as_bytes(); let key = create_secret_key(CHACHA20_POLY1305.key_len()); let encrypted_data = create_encrypted_data(data, &key); - let mut reader = RingCryptoRead::new(Cursor::new(encrypted_data), &CHACHA20_POLY1305, &key); + let mut reader = + RingCryptoRead::new(Cursor::new(encrypted_data), &CHACHA20_POLY1305, &key, false); let mut buf = vec![0u8; block_size]; for _ in 0..num_blocks { assert_eq!(reader.read(&mut buf).unwrap(), BLOCK_SIZE); @@ -102,7 +104,8 @@ fn test_partial_read() { let data = binding.as_bytes(); let key = create_secret_key(CHACHA20_POLY1305.key_len()); let encrypted_data = create_encrypted_data(data, &key); - let mut reader = RingCryptoRead::new(Cursor::new(encrypted_data), &CHACHA20_POLY1305, &key); + let mut reader = + RingCryptoRead::new(Cursor::new(encrypted_data), &CHACHA20_POLY1305, &key, false); let mut buf = vec![0u8; BLOCK_SIZE / 2]; assert_eq!(reader.read(&mut buf).unwrap(), BLOCK_SIZE / 2); } @@ -116,7 +119,7 @@ fn test_read_one_byte_less_than_block() { use std::io::Read; let data = vec![0u8; NONCE_LEN + BLOCK_SIZE + CHACHA20_POLY1305.tag_len() - 1]; let key = create_secret_key(CHACHA20_POLY1305.key_len()); - let mut reader = RingCryptoRead::new(Cursor::new(data), &CHACHA20_POLY1305, &key); + let mut reader = RingCryptoRead::new(Cursor::new(data), &CHACHA20_POLY1305, &key, false); let mut buf = vec![0u8; BLOCK_SIZE]; assert!(reader.read(&mut buf).is_err()); } @@ -137,7 +140,8 @@ fn test_alternating_small_and_large_reads() { let data = binding.as_bytes(); let key = create_secret_key(CHACHA20_POLY1305.key_len()); let encrypted_data = create_encrypted_data(data, &key); - let mut reader = RingCryptoRead::new(Cursor::new(encrypted_data), &CHACHA20_POLY1305, &key); + let mut reader = + RingCryptoRead::new(Cursor::new(encrypted_data), &CHACHA20_POLY1305, &key, false); let mut small_buf = vec![0u8; 10]; let mut large_buf = vec![0u8; 40]; assert_eq!(reader.read(&mut small_buf).unwrap(), 10); @@ -158,7 +162,7 @@ fn test_read_one_byte_more_than_block() { use std::io::Read; let data = vec![0u8; NONCE_LEN + BLOCK_SIZE + CHACHA20_POLY1305.tag_len() + 1]; let key = create_secret_key(CHACHA20_POLY1305.key_len()); - let mut reader = RingCryptoRead::new(Cursor::new(data), &CHACHA20_POLY1305, &key); + let mut reader = RingCryptoRead::new(Cursor::new(data), &CHACHA20_POLY1305, &key, false); let mut buf = vec![0u8; BLOCK_SIZE]; assert!(reader.read(&mut buf).is_err()); } @@ -183,13 +187,13 @@ fn test_ring_crypto_read_seek_chacha() { let key = SecretVec::new(Box::new(vec![0; algorithm.key_len()])); // write the data - let mut writer = RingCryptoWrite::new(cursor, false, algorithm, &key); + let mut writer = RingCryptoWrite::new(cursor, false, algorithm, &key, false); writer.write_all(data.as_bytes()).unwrap(); cursor = writer.finish().unwrap(); // Create a RingCryptoReaderSeek cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = RingCryptoRead::new(&mut cursor, algorithm, &key); + let mut reader = RingCryptoRead::new(&mut cursor, algorithm, &key, false); // Seek to the middle of the data reader.seek(SeekFrom::Start(7)).unwrap(); @@ -231,13 +235,13 @@ fn test_ring_crypto_read_seek_aes() { let key = SecretVec::new(Box::new(vec![0; algorithm.key_len()])); // write the data - let mut writer = RingCryptoWrite::new(cursor, true, algorithm, &key); + let mut writer = RingCryptoWrite::new(cursor, true, algorithm, &key, false); writer.write_all(data.as_bytes()).unwrap(); cursor = writer.finish().unwrap(); // Create a RingCryptoReaderSeek cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = RingCryptoRead::new_seek(cursor, algorithm, &key); + let mut reader = RingCryptoRead::new_seek(cursor, algorithm, &key, false); // Seek to the middle of the data reader.seek(SeekFrom::Start(7)).unwrap(); @@ -282,13 +286,13 @@ fn test_ring_crypto_read_seek_blocks_chacha() { let key = SecretVec::new(Box::new(vec![0; algorithm.key_len()])); // write the data - let mut writer = RingCryptoWrite::new(cursor, false, algorithm, &key); + let mut writer = RingCryptoWrite::new(cursor, false, algorithm, &key, false); writer.write_all(&data).unwrap(); cursor = writer.finish().unwrap(); // Create a RingCryptoReaderSeek cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = RingCryptoRead::new_seek(&mut cursor, algorithm, &key); + let mut reader = RingCryptoRead::new_seek(&mut cursor, algorithm, &key, false); // Seek in the second block reader.seek(SeekFrom::Start(BLOCK_SIZE as u64)).unwrap(); @@ -333,13 +337,13 @@ fn test_ring_crypto_read_seek_blocks_aes() { let key = SecretVec::new(Box::new(vec![0; algorithm.key_len()])); // write the data - let mut writer = RingCryptoWrite::new(cursor, true, algorithm, &key); + let mut writer = RingCryptoWrite::new(cursor, true, algorithm, &key, false); writer.write_all(&data).unwrap(); cursor = writer.finish().unwrap(); // Create a RingCryptoReaderSeek cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = RingCryptoRead::new_seek(cursor, algorithm, &key); + let mut reader = RingCryptoRead::new_seek(cursor, algorithm, &key, false); // Seek in the second block reader.seek(SeekFrom::Start(BLOCK_SIZE as u64)).unwrap(); @@ -384,13 +388,13 @@ fn test_ring_crypto_read_seek_blocks_boundary_chacha() { let key = SecretVec::new(Box::new(vec![0; algorithm.key_len()])); // write the data - let mut writer = RingCryptoWrite::new(cursor, false, algorithm, &key); + let mut writer = RingCryptoWrite::new(cursor, false, algorithm, &key, false); writer.write_all(&data).unwrap(); cursor = writer.finish().unwrap(); // Create a RingCryptoReaderSeek cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = RingCryptoRead::new_seek(&mut cursor, algorithm, &key); + let mut reader = RingCryptoRead::new_seek(&mut cursor, algorithm, &key, false); reader.read_exact(&mut [0; 1]).unwrap(); // Seek to the second block boundary @@ -432,13 +436,13 @@ fn test_ring_crypto_read_seek_blocks_boundary_aes() { let key = SecretVec::new(Box::new(vec![0; algorithm.key_len()])); // write the data - let mut writer = RingCryptoWrite::new(cursor, true, algorithm, &key); + let mut writer = RingCryptoWrite::new(cursor, true, algorithm, &key, false); writer.write_all(&data).unwrap(); cursor = writer.finish().unwrap(); // Create a RingCryptoReaderSeek cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = RingCryptoRead::new_seek(cursor, algorithm, &key); + let mut reader = RingCryptoRead::new_seek(cursor, algorithm, &key, false); reader.read_exact(&mut [0; 1]).unwrap(); // Seek to the second block boundary @@ -480,13 +484,13 @@ fn test_ring_crypto_read_seek_skip_blocks_chacha() { let key = SecretVec::new(Box::new(vec![0; algorithm.key_len()])); // write the data - let mut writer = RingCryptoWrite::new(cursor, false, algorithm, &key); + let mut writer = RingCryptoWrite::new(cursor, false, algorithm, &key, false); writer.write_all(&data).unwrap(); cursor = writer.finish().unwrap(); // Create a RingCryptoReaderSeek cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = RingCryptoRead::new_seek(cursor, algorithm, &key); + let mut reader = RingCryptoRead::new_seek(cursor, algorithm, &key, false); reader.seek(SeekFrom::Start(2 * BLOCK_SIZE as u64)).unwrap(); let mut buffer = vec![0; BLOCK_SIZE]; @@ -516,13 +520,13 @@ fn test_ring_crypto_read_seek_skip_blocks_aes() { let key = SecretVec::new(Box::new(vec![0; algorithm.key_len()])); // write the data - let mut writer = RingCryptoWrite::new(cursor, false, algorithm, &key); + let mut writer = RingCryptoWrite::new(cursor, false, algorithm, &key, false); writer.write_all(&data).unwrap(); cursor = writer.finish().unwrap(); // Create a RingCryptoReaderSeek cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = RingCryptoRead::new_seek(cursor, algorithm, &key); + let mut reader = RingCryptoRead::new_seek(cursor, algorithm, &key, false); reader.seek(SeekFrom::Start(2 * BLOCK_SIZE as u64)).unwrap(); let mut buffer = vec![0; BLOCK_SIZE]; @@ -552,13 +556,13 @@ fn test_ring_crypto_read_seek_in_second_block() { let key = SecretVec::new(Box::new(vec![0; algorithm.key_len()])); // write the data - let mut writer = RingCryptoWrite::new(cursor, false, algorithm, &key); + let mut writer = RingCryptoWrite::new(cursor, false, algorithm, &key, false); writer.write_all(&data).unwrap(); cursor = writer.finish().unwrap(); // Create a RingCryptoReaderSeek cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = RingCryptoRead::new_seek(cursor, algorithm, &key); + let mut reader = RingCryptoRead::new_seek(cursor, algorithm, &key, false); assert_eq!( reader.seek(SeekFrom::Start(BLOCK_SIZE as u64)).unwrap(), @@ -571,8 +575,12 @@ fn test_ring_crypto_read_seek_in_second_block() { fn finish_seek() { use super::RingCryptoRead; let reader = io::Cursor::new(vec![0; 10]); - let mut reader = - RingCryptoRead::new_seek(reader, &AES_256_GCM, &SecretVec::new(Box::new(vec![0; 32]))); + let mut reader = RingCryptoRead::new_seek( + reader, + &AES_256_GCM, + &SecretVec::new(Box::new(vec![0; 32])), + false, + ); let mut reader = reader.into_inner(); let _ = reader.seek(io::SeekFrom::Start(0)); } @@ -601,7 +609,7 @@ fn reader_only_read() { let key = SecretVec::new(Box::new(key)); let reader = ReadOnly {}; - let _reader = crypto::create_read(reader, cipher, &key); + let _reader = crypto::create_read(reader, cipher, &key, false); // we are not Seek, this would fail compilation // _reader.seek(io::SeekFrom::Start(0)).unwrap(); } @@ -627,14 +635,14 @@ fn reader_with_seeks() { let len = BLOCK_SIZE * 3 + 42; let cursor = io::Cursor::new(vec![0; 0]); - let mut writer = crypto::create_write(cursor, cipher, &key); + let mut writer = crypto::create_write(cursor, cipher, &key, false); let mut cursor_random = io::Cursor::new(vec![0; len]); rand::thread_rng().fill_bytes(cursor_random.get_mut()); io::copy(&mut cursor_random, &mut writer).unwrap(); let mut cursor = writer.finish().unwrap(); cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read_seek(cursor, cipher, &key); + let mut reader = crypto::create_read_seek(cursor, cipher, &key, false); reader.seek(SeekFrom::Start(42)).unwrap(); assert_eq!(reader.stream_position().unwrap(), 42); } diff --git a/src/crypto/write.rs b/src/crypto/write.rs index 901e0091..539d1c66 100644 --- a/src/crypto/write.rs +++ b/src/crypto/write.rs @@ -32,7 +32,7 @@ impl WriteSeekRead for T {} /// If you have your custom implementation for [Write] you want to pass to [`CryptoWrite`] it needs to implement this trait. /// -/// It has a blanket implementation for [Write] + [Seek] + [Read] + [`'static`] but in case your implementation is only [Write] it needs to implement this. +/// It has a blanket implementation for [Write] + [Seek] + [Read] + `'static` but in case your implementation is only [Write] it needs to implement this. pub trait CryptoInnerWriter: Write + Any { fn into_any(self) -> Box; fn as_write(&mut self) -> Option<&mut dyn Write>; @@ -78,6 +78,7 @@ pub struct RingCryptoWrite { opening_key: Option>, last_nonce: Option>>>>, decrypt_buf: Option, + pub is_compressed: bool, } impl RingCryptoWrite { @@ -88,6 +89,7 @@ impl RingCryptoWrite { seek: bool, algorithm: &'static Algorithm, key: &SecretVec, + is_compressed: bool, ) -> Self { let unbound_key = UnboundKey::new(algorithm, &key.expose_secret()).expect("unbound key"); let nonce_sequence = Arc::new(Mutex::new(RandomNonceSequence::default())); @@ -100,7 +102,13 @@ impl RingCryptoWrite { let unbound_key = UnboundKey::new(algorithm, &key.expose_secret()).unwrap(); let nonce_sequence2 = ExistingNonceSequence::new(last_nonce.clone()); let opening_key = OpeningKey::new(unbound_key, nonce_sequence2); - let ciphertext_block_size = NONCE_LEN + BLOCK_SIZE + algorithm.tag_len(); + + let ciphertext_block_size = if is_compressed { + NONCE_LEN + 4 + BLOCK_SIZE + algorithm.tag_len() + } else { + NONCE_LEN + BLOCK_SIZE + algorithm.tag_len() + }; + let decrypt_buf = BufMut::new(vec![0; ciphertext_block_size]); (Some(last_nonce), Some(opening_key), Some(decrypt_buf)) @@ -113,22 +121,40 @@ impl RingCryptoWrite { sealing_key, buf, nonce_sequence, - ciphertext_block_size: NONCE_LEN + BLOCK_SIZE + algorithm.tag_len(), + ciphertext_block_size: if is_compressed { + NONCE_LEN + 4 + BLOCK_SIZE + algorithm.tag_len() + } else { + NONCE_LEN + BLOCK_SIZE + algorithm.tag_len() + }, plaintext_block_size: BLOCK_SIZE, block_index: 0, opening_key, last_nonce, decrypt_buf, + is_compressed, } } fn encrypt_and_write(&mut self) -> io::Result<()> { - let data = self.buf.as_mut(); - let aad = Aad::from(self.block_index.to_le_bytes()); + let original_data = self.buf.as_mut(); + + let mut aad_bytes = self.block_index.to_le_bytes().to_vec(); + let mut data_to_encrypt; + let mut comp_len = 0u32; + + if self.is_compressed { + data_to_encrypt = lz4_flex::compress_prepend_size(original_data); + comp_len = data_to_encrypt.len() as u32; + aad_bytes.extend_from_slice(&comp_len.to_le_bytes()); + } else { + data_to_encrypt = original_data.to_vec(); + } + + let aad = Aad::from(aad_bytes); let tag = self .sealing_key - .seal_in_place_separate_tag(aad, data) + .seal_in_place_separate_tag(aad, &mut data_to_encrypt) .map_err(|err| io::Error::other(format!("error sealing in place: {err}")))?; // Ensure tag is properly extracted let nonce_sequence = self.nonce_sequence.lock().unwrap(); @@ -137,10 +163,26 @@ impl RingCryptoWrite { .writer .as_mut() .ok_or_else(|| io::Error::new(io::ErrorKind::NotConnected, "no writer"))?; + writer.write_all(nonce)?; - writer.write_all(data)?; + + if self.is_compressed { + writer.write_all(&comp_len.to_le_bytes())?; + } + + writer.write_all(&data_to_encrypt)?; + self.buf.clear(); writer.write_all(tag.as_ref())?; + + if self.is_compressed { + let written_so_far = NONCE_LEN + 4 + comp_len as usize + tag.as_ref().len(); + let padding = self.ciphertext_block_size.saturating_sub(written_so_far); + if padding > 0 { + writer.write_all(&vec![0; padding])?; + } + } + writer.flush()?; self.block_index += 1; Ok(()) @@ -166,7 +208,8 @@ impl RingCryptoWrite { self.decrypt_buf.as_mut().unwrap(), writer, self.last_nonce.as_ref().unwrap(), - self.opening_key.as_mut().unwrap() + self.opening_key.as_mut().unwrap(), + self.is_compressed ); if old_block_index == self.block_index { // no decryption happened @@ -382,7 +425,7 @@ impl Seek for RingCryptoWrite { self.block_index = 0; self.decrypt_block()?; } - let at_full_block_end = self.pos() % self.plaintext_block_size as u64 == 0 + let at_full_block_end = self.pos().is_multiple_of(self.plaintext_block_size as u64) && self.buf.pos_write() == self.buf.available(); if self.buf.available() == 0 // this checks if we are at the end of the current block, diff --git a/src/crypto/write/bench.rs b/src/crypto/write/bench.rs index 7e17b5a5..6750ba97 100644 --- a/src/crypto/write/bench.rs +++ b/src/crypto/write/bench.rs @@ -25,7 +25,8 @@ fn bench_writer_1mb_cha_cha20poly1305_file(b: &mut Bencher) { b.iter(|| { black_box({ let mut reader = rnd_reader.clone(); - let mut writer = crypto::create_write(tempfile::tempfile().unwrap(), cipher, &key); + let mut writer = + crypto::create_write(tempfile::tempfile().unwrap(), cipher, &key, true); io::copy(&mut reader, &mut writer).unwrap(); writer.finish().unwrap() }) @@ -56,7 +57,8 @@ fn bench_writer_1mb_aes256gcm_file(b: &mut Bencher) { b.iter(|| { black_box({ let mut reader = rnd_reader.clone(); - let mut writer = crypto::create_write(tempfile::tempfile().unwrap(), cipher, &key); + let mut writer = + crypto::create_write(tempfile::tempfile().unwrap(), cipher, &key, true); io::copy(&mut reader, &mut writer).unwrap(); writer.finish().unwrap() }) @@ -88,7 +90,7 @@ fn bench_writer_1mb_cha_cha20poly1305_mem(b: &mut Bencher) { black_box({ let mut reader = rnd_reader.clone(); let cursor_write = io::Cursor::new(vec![]); - let mut writer = crypto::create_write(cursor_write, cipher, &key); + let mut writer = crypto::create_write(cursor_write, cipher, &key, true); io::copy(&mut reader, &mut writer).unwrap(); writer.finish().unwrap() }) @@ -120,7 +122,7 @@ fn bench_writer_1mb_aes256gcm_mem(b: &mut Bencher) { black_box({ let mut reader = rnd_reader.clone(); let cursor_write = io::Cursor::new(vec![]); - let mut writer = crypto::create_write(cursor_write, cipher, &key); + let mut writer = crypto::create_write(cursor_write, cipher, &key, true); io::copy(&mut reader, &mut writer).unwrap(); writer.finish().unwrap() }) diff --git a/src/crypto/write/test.rs b/src/crypto/write/test.rs index 3a5bcb9d..b7f786c9 100644 --- a/src/crypto/write/test.rs +++ b/src/crypto/write/test.rs @@ -53,7 +53,7 @@ fn test_encryption() { let cipher = Cipher::ChaCha20Poly1305; let key = create_secret_key(cipher.key_len()); - let mut crypto_writer = crypto::create_write(writer, cipher, &key); + let mut crypto_writer = crypto::create_write(writer, cipher, &key, false); let data = b"hello, world!"; crypto_writer.write_all(data).unwrap(); @@ -74,7 +74,7 @@ fn test_basic_write() { let cipher = Cipher::ChaCha20Poly1305; let key = create_secret_key(cipher.key_len()); - let mut crypto_writer = crypto::create_write(writer, cipher, &key); + let mut crypto_writer = crypto::create_write(writer, cipher, &key, false); let data = b"hello, world!"; @@ -95,7 +95,7 @@ fn test_flush() { let cipher = &CHACHA20_POLY1305; let key = create_secret_key(cipher.key_len()); - let mut crypto_writer = RingCryptoWrite::new(writer, false, cipher, &key); + let mut crypto_writer = RingCryptoWrite::new(writer, false, cipher, &key, false); let data = b"Hello, world!"; @@ -117,7 +117,7 @@ fn test_write_after_finish() { let cipher = &CHACHA20_POLY1305; let key = create_secret_key(cipher.key_len()); - let mut crypto_writer = RingCryptoWrite::new(writer, false, cipher, &key); + let mut crypto_writer = RingCryptoWrite::new(writer, false, cipher, &key, false); let data = b"Hello, world!"; @@ -134,7 +134,7 @@ fn test_encrypt_and_write_nonce_uniqueness() { use std::io::{Cursor, Write}; let writer = Cursor::new(Vec::new()); let key = create_secret_key(CHACHA20_POLY1305.key_len()); - let mut crypto_writer = RingCryptoWrite::new(writer, false, &CHACHA20_POLY1305, &key); + let mut crypto_writer = RingCryptoWrite::new(writer, false, &CHACHA20_POLY1305, &key, false); crypto_writer.write_all(&[0u8; BLOCK_SIZE]).unwrap(); crypto_writer.write_all(&[0u8; BLOCK_SIZE]).unwrap(); @@ -153,7 +153,7 @@ fn test_pos_initial() { use std::io::Cursor; let writer = Cursor::new(Vec::new()); let key = create_secret_key(CHACHA20_POLY1305.key_len()); - let crypto_writer = RingCryptoWrite::new(writer, false, &CHACHA20_POLY1305, &key); + let crypto_writer = RingCryptoWrite::new(writer, false, &CHACHA20_POLY1305, &key, false); assert_eq!(crypto_writer.pos(), 0); } @@ -166,7 +166,7 @@ fn test_pos_after_write() { use std::io::{Cursor, Write}; let writer = Cursor::new(Vec::new()); let key = create_secret_key(CHACHA20_POLY1305.key_len()); - let mut crypto_writer = RingCryptoWrite::new(writer, false, &CHACHA20_POLY1305, &key); + let mut crypto_writer = RingCryptoWrite::new(writer, false, &CHACHA20_POLY1305, &key, false); crypto_writer.write_all(b"Hello, World!").unwrap(); assert_eq!(crypto_writer.pos(), 13); @@ -180,7 +180,7 @@ fn test_pos_after_multiple_writes() { use std::io::{Cursor, Write}; let writer = Cursor::new(Vec::new()); let key = create_secret_key(CHACHA20_POLY1305.key_len()); - let mut crypto_writer = RingCryptoWrite::new(writer, false, &CHACHA20_POLY1305, &key); + let mut crypto_writer = RingCryptoWrite::new(writer, false, &CHACHA20_POLY1305, &key, false); crypto_writer.write_all(b"Hello").unwrap(); crypto_writer.write_all(b", ").unwrap(); @@ -196,7 +196,7 @@ fn test_pos_after_seek() { use std::io::{Cursor, Write}; let writer = Cursor::new(Vec::new()); let key = create_secret_key(CHACHA20_POLY1305.key_len()); - let mut crypto_writer = RingCryptoWrite::new(writer, true, &CHACHA20_POLY1305, &key); + let mut crypto_writer = RingCryptoWrite::new(writer, true, &CHACHA20_POLY1305, &key, false); crypto_writer.write_all(b"Hello, World!").unwrap(); crypto_writer.seek(SeekFrom::Start(7)).unwrap(); @@ -211,7 +211,7 @@ fn test_pos_after_seek_beyond_end() { use std::io::{Cursor, Write}; let writer = Cursor::new(Vec::new()); let key = create_secret_key(CHACHA20_POLY1305.key_len()); - let mut crypto_writer = RingCryptoWrite::new(writer, true, &CHACHA20_POLY1305, &key); + let mut crypto_writer = RingCryptoWrite::new(writer, true, &CHACHA20_POLY1305, &key, false); crypto_writer.write_all(b"Hello, World!").unwrap(); crypto_writer.seek(SeekFrom::End(10)).unwrap(); @@ -226,7 +226,7 @@ fn test_pos_after_write_full_block() { use std::io::{Cursor, Write}; let writer = Cursor::new(Vec::new()); let key = create_secret_key(CHACHA20_POLY1305.key_len()); - let mut crypto_writer = RingCryptoWrite::new(writer, false, &CHACHA20_POLY1305, &key); + let mut crypto_writer = RingCryptoWrite::new(writer, false, &CHACHA20_POLY1305, &key, false); let full_block = vec![0u8; crypto_writer.plaintext_block_size]; crypto_writer.write_all(&full_block).unwrap(); @@ -244,7 +244,7 @@ fn test_pos_after_write_multiple_blocks() { use std::io::{Cursor, Write}; let writer = Cursor::new(Vec::new()); let key = create_secret_key(CHACHA20_POLY1305.key_len()); - let mut crypto_writer = RingCryptoWrite::new(writer, false, &CHACHA20_POLY1305, &key); + let mut crypto_writer = RingCryptoWrite::new(writer, false, &CHACHA20_POLY1305, &key, false); let data = vec![0u8; crypto_writer.plaintext_block_size * 3 + 100]; crypto_writer.write_all(&data).unwrap(); @@ -262,7 +262,7 @@ fn test_pos_after_seek_and_write() { use std::io::{Cursor, Write}; let writer = Cursor::new(Vec::new()); let key = create_secret_key(CHACHA20_POLY1305.key_len()); - let mut crypto_writer = RingCryptoWrite::new(writer, true, &CHACHA20_POLY1305, &key); + let mut crypto_writer = RingCryptoWrite::new(writer, true, &CHACHA20_POLY1305, &key, false); crypto_writer.write_all(b"Hello, World!").unwrap(); crypto_writer.seek(SeekFrom::Start(7)).unwrap(); @@ -278,7 +278,7 @@ fn test_pos_after_flush() { use std::io::{Cursor, Write}; let writer = Cursor::new(Vec::new()); let key = create_secret_key(CHACHA20_POLY1305.key_len()); - let mut crypto_writer = RingCryptoWrite::new(writer, false, &CHACHA20_POLY1305, &key); + let mut crypto_writer = RingCryptoWrite::new(writer, false, &CHACHA20_POLY1305, &key, false); crypto_writer.write_all(b"Hello, World!").unwrap(); crypto_writer.flush().unwrap(); @@ -293,7 +293,7 @@ fn test_pos_consistency_with_seek() { use std::io::{Cursor, Seek, Write}; let writer = Cursor::new(Vec::new()); let key = create_secret_key(CHACHA20_POLY1305.key_len()); - let mut crypto_writer = RingCryptoWrite::new(writer, true, &CHACHA20_POLY1305, &key); + let mut crypto_writer = RingCryptoWrite::new(writer, true, &CHACHA20_POLY1305, &key, false); crypto_writer.write_all(b"Hello, World!").unwrap(); let pos1 = crypto_writer.pos(); @@ -319,25 +319,25 @@ fn test_reader_writer_chacha() { // simple text let mut cursor = io::Cursor::new(vec![0; 0]); - let mut writer = crypto::create_write(cursor, cipher, &key); + let mut writer = crypto::create_write(cursor, cipher, &key, false); let data = "hello, this is my secret message"; writer.write_all(data.as_bytes()).unwrap(); cursor = writer.finish().unwrap(); cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(cursor, cipher, &key); + let mut reader = crypto::create_read(cursor, cipher, &key, false); let mut s = String::new(); reader.read_to_string(&mut s).unwrap(); assert_eq!(data, s); // larger data let mut cursor = io::Cursor::new(vec![]); - let mut writer = crypto::create_write(cursor, cipher, &key); + let mut writer = crypto::create_write(cursor, cipher, &key, false); let mut data: [u8; BLOCK_SIZE + 42] = [0; BLOCK_SIZE + 42]; rand::thread_rng().fill_bytes(&mut data); writer.write_all(&data).unwrap(); cursor = writer.finish().unwrap(); cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(cursor, cipher, &key); + let mut reader = crypto::create_read(cursor, cipher, &key, false); let mut data2 = vec![]; reader.read_to_end(&mut data2).unwrap(); assert_eq!(data.len(), data2.len()); @@ -363,14 +363,14 @@ fn test_reader_writer_1mb_chacha() { let len = 1024 * 1024; let mut cursor = io::Cursor::new(vec![0; 0]); - let mut writer = crypto::create_write(cursor, cipher, &key); + let mut writer = crypto::create_write(cursor, cipher, &key, false); let mut cursor_random = io::Cursor::new(vec![0; len]); rand::thread_rng().fill_bytes(cursor_random.get_mut()); io::copy(&mut cursor_random, &mut writer).unwrap(); cursor = writer.finish().unwrap(); cursor_random.seek(SeekFrom::Start(0)).unwrap(); cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(cursor, cipher, &key); + let mut reader = crypto::create_read(cursor, cipher, &key, false); let hash1 = crypto::hash_reader(&mut cursor_random).unwrap(); let hash2 = crypto::hash_reader(&mut reader).unwrap(); assert_eq!(hash1, hash2); @@ -394,25 +394,25 @@ fn test_reader_writer_aes() { // simple text let mut cursor = io::Cursor::new(vec![0; 0]); - let mut writer = crypto::create_write(cursor, cipher, &key); + let mut writer = crypto::create_write(cursor, cipher, &key, false); let data = "hello, this is my secret message"; writer.write_all(data.as_bytes()).unwrap(); cursor = writer.finish().unwrap(); cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(cursor, cipher, &key); + let mut reader = crypto::create_read(cursor, cipher, &key, false); let mut s = String::new(); reader.read_to_string(&mut s).unwrap(); assert_eq!(data, s); // larger data let mut cursor = io::Cursor::new(vec![]); - let mut writer = crypto::create_write(cursor, cipher, &key); + let mut writer = crypto::create_write(cursor, cipher, &key, false); let mut data: [u8; BLOCK_SIZE + 42] = [0; BLOCK_SIZE + 42]; rand::thread_rng().fill_bytes(&mut data); writer.write_all(&data).unwrap(); cursor = writer.finish().unwrap(); cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(cursor, cipher, &key); + let mut reader = crypto::create_read(cursor, cipher, &key, false); let mut data2 = vec![]; reader.read_to_end(&mut data2).unwrap(); assert_eq!(data.len(), data2.len()); @@ -438,14 +438,14 @@ fn test_reader_writer_1mb_aes() { let len = 1024 * 1024; let mut cursor = io::Cursor::new(vec![0; 0]); - let mut writer = crypto::create_write(cursor, cipher, &key); + let mut writer = crypto::create_write(cursor, cipher, &key, false); let mut cursor_random = io::Cursor::new(vec![0; len]); rand::thread_rng().fill_bytes(cursor_random.get_mut()); io::copy(&mut cursor_random, &mut writer).unwrap(); cursor = writer.finish().unwrap(); cursor_random.seek(SeekFrom::Start(0)).unwrap(); cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(cursor, cipher, &key); + let mut reader = crypto::create_read(cursor, cipher, &key, false); let hash1 = crypto::hash_reader(&mut cursor_random).unwrap(); let hash2 = crypto::hash_reader(&mut reader).unwrap(); assert_eq!(hash1, hash2); @@ -468,7 +468,7 @@ fn test_writer_seek_text_chacha() { let key = create_secret_key(cipher.key_len()); let mut cursor = io::Cursor::new(vec![0; 0]); - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer .write_all(b"This is a test message for the seek capability") .unwrap(); @@ -478,7 +478,7 @@ fn test_writer_seek_text_chacha() { writer.write_all(b"THE").unwrap(); cursor = writer.finish().unwrap(); cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(cursor, cipher, &key); + let mut reader = crypto::create_read(cursor, cipher, &key, false); let mut s = String::new(); reader.read_to_string(&mut s).unwrap(); cursor = reader.into_inner(); @@ -486,12 +486,12 @@ fn test_writer_seek_text_chacha() { // open existing content cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.seek(SeekFrom::Start(10)).unwrap(); writer.write_all(b"TEST").unwrap(); cursor = writer.finish().unwrap(); cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(cursor, cipher, &key); + let mut reader = crypto::create_read(cursor, cipher, &key, false); let mut s = String::new(); reader.read_to_string(&mut s).unwrap(); cursor = reader.into_inner(); @@ -499,12 +499,12 @@ fn test_writer_seek_text_chacha() { // seek current cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.seek(SeekFrom::Current(15)).unwrap(); writer.write_all(b"MESSAGE").unwrap(); cursor = writer.finish().unwrap(); cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(cursor, cipher, &key); + let mut reader = crypto::create_read(cursor, cipher, &key, false); let mut s = String::new(); reader.read_to_string(&mut s).unwrap(); cursor = reader.into_inner(); @@ -512,12 +512,12 @@ fn test_writer_seek_text_chacha() { // seek from the end cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.seek(SeekFrom::End(-15)).unwrap(); writer.write_all(b"SEEK").unwrap(); cursor = writer.finish().unwrap(); cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(cursor, cipher, &key); + let mut reader = crypto::create_read(cursor, cipher, &key, false); let mut s = String::new(); reader.read_to_string(&mut s).unwrap(); cursor = reader.into_inner(); @@ -525,17 +525,17 @@ fn test_writer_seek_text_chacha() { // seek < 0 cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); assert!(writer.seek(SeekFrom::Current(-1)).is_err()); cursor = writer.finish().unwrap(); // seek after content size cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.seek(SeekFrom::End(1)).unwrap(); cursor = writer.finish().unwrap(); cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(cursor, cipher, &key); + let mut reader = crypto::create_read(cursor, cipher, &key, false); let mut s = String::new(); reader.read_to_string(&mut s).unwrap(); reader.into_inner(); @@ -545,7 +545,7 @@ fn test_writer_seek_text_chacha() { ); let mut cursor = io::Cursor::new(vec![0; 0]); - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); let mut buf: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; writer.write_all(&buf).unwrap(); writer.seek(SeekFrom::Start(5)).unwrap(); @@ -554,7 +554,7 @@ fn test_writer_seek_text_chacha() { writer.write_all(&[2, 2]).unwrap(); cursor = writer.finish().unwrap(); cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(cursor, cipher, &key); + let mut reader = crypto::create_read(cursor, cipher, &key, false); let mut buf2 = [0; 10]; reader.read_exact(&mut buf2).unwrap(); cursor = reader.into_inner(); @@ -566,12 +566,12 @@ fn test_writer_seek_text_chacha() { // open existing content cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.seek(SeekFrom::Start(3)).unwrap(); writer.write_all(&[3, 3]).unwrap(); cursor = writer.finish().unwrap(); cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(cursor, cipher, &key); + let mut reader = crypto::create_read(cursor, cipher, &key, false); buf[3] = 3; buf[4] = 3; let mut buf2 = [0; 10]; @@ -597,7 +597,7 @@ fn test_writer_seek_text_aes() { let key = create_secret_key(cipher.key_len()); let mut cursor = io::Cursor::new(vec![0; 0]); - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer .write_all(b"This is a test message for the seek capability") .unwrap(); @@ -607,7 +607,7 @@ fn test_writer_seek_text_aes() { writer.write_all(b"THE").unwrap(); cursor = writer.finish().unwrap(); cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(cursor, cipher, &key); + let mut reader = crypto::create_read(cursor, cipher, &key, false); let mut s = String::new(); reader.read_to_string(&mut s).unwrap(); cursor = reader.into_inner(); @@ -615,12 +615,12 @@ fn test_writer_seek_text_aes() { // open existing content cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.seek(SeekFrom::Start(10)).unwrap(); writer.write_all(b"TEST").unwrap(); cursor = writer.finish().unwrap(); cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(cursor, cipher, &key); + let mut reader = crypto::create_read(cursor, cipher, &key, false); let mut s = String::new(); reader.read_to_string(&mut s).unwrap(); cursor = reader.into_inner(); @@ -628,12 +628,12 @@ fn test_writer_seek_text_aes() { // seek current cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.seek(SeekFrom::Current(15)).unwrap(); writer.write_all(b"MESSAGE").unwrap(); cursor = writer.finish().unwrap(); cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(cursor, cipher, &key); + let mut reader = crypto::create_read(cursor, cipher, &key, false); let mut s = String::new(); reader.read_to_string(&mut s).unwrap(); cursor = reader.into_inner(); @@ -641,12 +641,12 @@ fn test_writer_seek_text_aes() { // seek from the end cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.seek(SeekFrom::End(-15)).unwrap(); writer.write_all(b"SEEK").unwrap(); cursor = writer.finish().unwrap(); cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(cursor, cipher, &key); + let mut reader = crypto::create_read(cursor, cipher, &key, false); let mut s = String::new(); reader.read_to_string(&mut s).unwrap(); cursor = reader.into_inner(); @@ -654,17 +654,17 @@ fn test_writer_seek_text_aes() { // seek < 0 cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); assert!(writer.seek(SeekFrom::Current(-1)).is_err()); cursor = writer.finish().unwrap(); // seek after content size cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.seek(SeekFrom::End(1)).unwrap(); cursor = writer.finish().unwrap(); cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(cursor, cipher, &key); + let mut reader = crypto::create_read(cursor, cipher, &key, false); let mut s = String::new(); reader.read_to_string(&mut s).unwrap(); reader.into_inner(); @@ -674,7 +674,7 @@ fn test_writer_seek_text_aes() { ); let mut cursor = io::Cursor::new(vec![0; 0]); - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); let mut buf: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; writer.write_all(&buf).unwrap(); writer.seek(SeekFrom::Start(5)).unwrap(); @@ -683,7 +683,7 @@ fn test_writer_seek_text_aes() { writer.write_all(&[2, 2]).unwrap(); cursor = writer.finish().unwrap(); cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(cursor, cipher, &key); + let mut reader = crypto::create_read(cursor, cipher, &key, false); let mut buf2 = [0; 10]; reader.read_exact(&mut buf2).unwrap(); cursor = reader.into_inner(); @@ -695,12 +695,12 @@ fn test_writer_seek_text_aes() { // open existing content cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.seek(SeekFrom::Start(3)).unwrap(); writer.write_all(&[3, 3]).unwrap(); cursor = writer.finish().unwrap(); cursor.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(cursor, cipher, &key); + let mut reader = crypto::create_read(cursor, cipher, &key, false); buf[3] = 3; buf[4] = 3; let mut buf2 = [0; 10]; @@ -730,7 +730,7 @@ fn test_writer_seek_blocks_chacha() { let data = [42]; let mut cursor = io::Cursor::new(vec![0; 0]); - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); let mut cursor_random = io::Cursor::new(vec![0; len]); rand::thread_rng().fill_bytes(cursor_random.get_mut()); io::copy(&mut cursor_random, &mut writer).unwrap(); @@ -745,7 +745,7 @@ fn test_writer_seek_blocks_chacha() { cursor = compare(&mut cursor_random, cursor, cipher, &key); // write something that extends to the second block - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.seek(SeekFrom::Start(42)).unwrap(); assert_eq!(writer.stream_position().unwrap(), 42); cursor_random.seek(SeekFrom::Start(42)).unwrap(); @@ -758,7 +758,7 @@ fn test_writer_seek_blocks_chacha() { cursor = compare(&mut cursor_random, cursor, cipher, &key); // write at the boundary of block - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.seek(SeekFrom::Start(BLOCK_SIZE as u64)).unwrap(); assert_eq!(writer.stream_position().unwrap(), BLOCK_SIZE as u64); cursor_random @@ -770,7 +770,7 @@ fn test_writer_seek_blocks_chacha() { cursor = compare(&mut cursor_random, cursor, cipher, &key); // write after boundary of block - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.seek(SeekFrom::Start(BLOCK_SIZE as u64)).unwrap(); assert_eq!(writer.stream_position().unwrap(), BLOCK_SIZE as u64); cursor_random @@ -785,7 +785,7 @@ fn test_writer_seek_blocks_chacha() { cursor = compare(&mut cursor_random, cursor, cipher, &key); // write until block boundary then seek and write inside new block - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.write_all(&[0_u8; BLOCK_SIZE]).unwrap(); assert_eq!(writer.stream_position().unwrap(), BLOCK_SIZE as u64); cursor_random.write_all(&[0_u8; BLOCK_SIZE]).unwrap(); @@ -798,7 +798,7 @@ fn test_writer_seek_blocks_chacha() { cursor = compare(&mut cursor_random, cursor, cipher, &key); // seek from block boundary to block boundary - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.seek(SeekFrom::Start(BLOCK_SIZE as u64)).unwrap(); assert_eq!(writer.stream_position().unwrap(), BLOCK_SIZE as u64); cursor_random @@ -825,7 +825,7 @@ fn test_writer_seek_blocks_chacha() { cursor = compare(&mut cursor_random, cursor, cipher, &key); // seek after content size, make sure it writes zeros - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.seek(SeekFrom::End(42)).unwrap(); assert_eq!( writer.stream_position().unwrap(), @@ -838,7 +838,7 @@ fn test_writer_seek_blocks_chacha() { cursor = compare(&mut cursor_random, cursor, cipher, &key); // seek after content size, more blocks, make sure it writes zeros - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer .seek(SeekFrom::End(10 * BLOCK_SIZE as i64 + 43)) .unwrap(); @@ -855,7 +855,7 @@ fn test_writer_seek_blocks_chacha() { cursor = compare(&mut cursor_random, cursor, cipher, &key); // write something after the end then seek after the end, after write we should have a bigger end - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.seek(SeekFrom::End(42)).unwrap(); assert_eq!( writer.stream_position().unwrap(), @@ -903,7 +903,7 @@ fn test_writer_seek_blocks_aes() { let data = [42]; let mut cursor = io::Cursor::new(vec![0; 0]); - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); let mut cursor_random = io::Cursor::new(vec![0; len]); rand::thread_rng().fill_bytes(cursor_random.get_mut()); io::copy(&mut cursor_random, &mut writer).unwrap(); @@ -918,7 +918,7 @@ fn test_writer_seek_blocks_aes() { cursor = compare(&mut cursor_random, cursor, cipher, &key); // write something that extends to the second block - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.seek(SeekFrom::Start(42)).unwrap(); assert_eq!(writer.stream_position().unwrap(), 42); cursor_random.seek(SeekFrom::Start(42)).unwrap(); @@ -931,7 +931,7 @@ fn test_writer_seek_blocks_aes() { cursor = compare(&mut cursor_random, cursor, cipher, &key); // write at the boundary of block - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.seek(SeekFrom::Start(BLOCK_SIZE as u64)).unwrap(); assert_eq!(writer.stream_position().unwrap(), BLOCK_SIZE as u64); cursor_random @@ -943,7 +943,7 @@ fn test_writer_seek_blocks_aes() { cursor = compare(&mut cursor_random, cursor, cipher, &key); // write after boundary of block - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.seek(SeekFrom::Start(BLOCK_SIZE as u64)).unwrap(); assert_eq!(writer.stream_position().unwrap(), BLOCK_SIZE as u64); cursor_random @@ -958,7 +958,7 @@ fn test_writer_seek_blocks_aes() { cursor = compare(&mut cursor_random, cursor, cipher, &key); // write until block boundary then seek and write inside new block - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.write_all(&[0_u8; BLOCK_SIZE]).unwrap(); assert_eq!(writer.stream_position().unwrap(), BLOCK_SIZE as u64); cursor_random.write_all(&[0_u8; BLOCK_SIZE]).unwrap(); @@ -971,7 +971,7 @@ fn test_writer_seek_blocks_aes() { cursor = compare(&mut cursor_random, cursor, cipher, &key); // seek from block boundary to block boundary - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.seek(SeekFrom::Start(BLOCK_SIZE as u64)).unwrap(); assert_eq!(writer.stream_position().unwrap(), BLOCK_SIZE as u64); cursor_random @@ -998,7 +998,7 @@ fn test_writer_seek_blocks_aes() { cursor = compare(&mut cursor_random, cursor, cipher, &key); // seek after content size, make sure it writes zeros - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.seek(SeekFrom::End(42)).unwrap(); assert_eq!( writer.stream_position().unwrap(), @@ -1011,7 +1011,7 @@ fn test_writer_seek_blocks_aes() { cursor = compare(&mut cursor_random, cursor, cipher, &key); // seek after content size, more blocks, make sure it writes zeros - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer .seek(SeekFrom::End(10 * BLOCK_SIZE as i64 + 43)) .unwrap(); @@ -1028,7 +1028,7 @@ fn test_writer_seek_blocks_aes() { cursor = compare(&mut cursor_random, cursor, cipher, &key); // write something after the end then seek after the end, after write we should have a bigger end - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); writer.seek(SeekFrom::End(42)).unwrap(); assert_eq!( writer.stream_position().unwrap(), @@ -1077,7 +1077,7 @@ fn test_writer_seek_blocks_one_go_chacha() { let data = [42]; let mut cursor = io::Cursor::new(vec![0; 0]); - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); let mut cursor_random = io::Cursor::new(vec![0; len]); rand::thread_rng().fill_bytes(cursor_random.get_mut()); io::copy(&mut cursor_random, &mut writer).unwrap(); @@ -1194,7 +1194,7 @@ fn test_writer_seek_blocks_one_go_aes() { let data = [42]; let mut cursor = io::Cursor::new(vec![0; 0]); - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); let mut cursor_random = io::Cursor::new(vec![0; len]); rand::thread_rng().fill_bytes(cursor_random.get_mut()); io::copy(&mut cursor_random, &mut writer).unwrap(); @@ -1298,7 +1298,7 @@ fn compare( ) -> io::Cursor> { plaintext.seek(SeekFrom::Start(0)).unwrap(); ciphertext.seek(SeekFrom::Start(0)).unwrap(); - let mut reader = crypto::create_read(ciphertext, cipher, key); + let mut reader = crypto::create_read(ciphertext, cipher, key, false); let hash1 = crypto::hash_reader(&mut plaintext).unwrap(); let hash2 = crypto::hash_reader(&mut reader).unwrap(); assert_eq!(hash1, hash2); @@ -1348,7 +1348,7 @@ fn writer_only_write() { let key = SecretVec::from(key); let writer = WriteOnly {}; - let _writer = crypto::create_write(writer, cipher, &key); + let _writer = crypto::create_write(writer, cipher, &key, false); // we are not Seek, this would fail compilation // _writer.seek(io::SeekFrom::Start(0)).unwrap(); } @@ -1373,7 +1373,7 @@ fn writer_with_seeks() { let len = BLOCK_SIZE * 3 + 42; let cursor = Cursor::new(vec![0; 0]); - let mut writer = crypto::create_write_seek(cursor, cipher, &key); + let mut writer = crypto::create_write_seek(cursor, cipher, &key, false); let mut cursor_random = io::Cursor::new(vec![0; len]); rand::thread_rng().fill_bytes(cursor_random.get_mut()); io::copy(&mut cursor_random, &mut writer).unwrap(); diff --git a/src/encryptedfs.rs b/src/encryptedfs.rs index 7c2da5a4..79f80d01 100644 --- a/src/encryptedfs.rs +++ b/src/encryptedfs.rs @@ -91,6 +91,9 @@ pub struct FileAttr { pub blksize: u32, /// Flags (macOS only, see chflags(2)) pub flags: u32, + + #[serde(default)] + pub is_compressed: bool, } /// File types. @@ -237,6 +240,7 @@ impl From for FileAttr { rdev: value.rdev, blksize: 0, flags: value.flags, + is_compressed: false, } } } @@ -858,6 +862,7 @@ impl EncryptedFs { File::open(hash_path)?, self.cipher, &*self.key.get().await?, + false, ))?; drop(guard); self.get_inode_from_cache_or_storage(ino).await.map(Some) @@ -1187,6 +1192,7 @@ impl EncryptedFs { file, self.cipher, &*self.key.get().await?, + false, )); drop(guard); if let Err(e) = res { @@ -1255,6 +1261,7 @@ impl EncryptedFs { file, self.cipher, &*self.key.get().await?, + false, ))?) } @@ -1891,9 +1898,11 @@ impl EncryptedFs { let mut file = fs_util::open_atomic_write(&file_path)?; { // have a new scope, so we drop the reader before moving new content files - let mut reader = self.create_read(File::open(file_path.as_path())?).await?; + let mut reader = self + .create_read(File::open(file_path.as_path())?, attr.is_compressed) + .await?; - let mut writer = self.create_write(file).await?; + let mut writer = self.create_write(file, attr.is_compressed).await?; let len = if size > attr.size { // increase size, copy existing data until existing size @@ -1972,17 +1981,18 @@ impl EncryptedFs { self.reset_handles(ino, Some(handle), true).await?; let write_handles_guard = self.write_handles.write().await; let mut ctx = write_handles_guard.get(&handle).unwrap().lock().await; + let full_attr = self.get_inode_from_storage(ino).await?; let writer = self .create_write_seek( OpenOptions::new() .read(true) .write(true) .open(self.contents_path(ino))?, + full_attr.is_compressed, // PASEAZĂ FLAG-UL AICI ) .await?; ctx.writer = Some(Box::new(writer)); - let attr = self.get_inode_from_storage(ino).await?; - ctx.attr = attr.into(); + ctx.attr = full_attr.into(); } } Ok(()) @@ -2085,11 +2095,13 @@ impl EncryptedFs { pub async fn create_write( &self, file: W, + is_compressed: bool, ) -> FsResult> { Ok(crypto::create_write( file, self.cipher, &*self.key.get().await?, + is_compressed, )) } @@ -2097,11 +2109,13 @@ impl EncryptedFs { pub async fn create_write_seek( &self, file: W, + is_compressed: bool, ) -> FsResult> { Ok(crypto::create_write_seek( file, self.cipher, &*self.key.get().await?, + is_compressed, )) } @@ -2109,11 +2123,13 @@ impl EncryptedFs { pub async fn create_read( &self, reader: R, + is_compressed: bool, ) -> FsResult> { Ok(crypto::create_read( reader, self.cipher, &*self.key.get().await?, + is_compressed, )) } @@ -2121,11 +2137,13 @@ impl EncryptedFs { pub async fn create_read_seek( &self, reader: R, + is_compressed: bool, ) -> FsResult> { Ok(crypto::create_read_seek( reader, self.cipher, &*self.key.get().await?, + is_compressed, )) } @@ -2143,7 +2161,7 @@ impl EncryptedFs { )?)?; let initial_key = crypto::derive_key(&old_password, cipher, &salt)?; let enc_file = data_dir.join(SECURITY_DIR).join(KEY_ENC_FILENAME); - let reader = crypto::create_read(File::open(enc_file)?, cipher, &initial_key); + let reader = crypto::create_read(File::open(enc_file)?, cipher, &initial_key, false); let key: Vec = bincode::deserialize_from(reader).map_err(|_| FsError::InvalidPassword)?; let key = SecretBox::new(Box::new(key)); @@ -2190,7 +2208,9 @@ impl EncryptedFs { self.set_attr(ino, set_attr).await?; let attr = self.get_inode_from_storage(ino).await?; let mut ctx = guard.get(handle).unwrap().lock().await; - let reader = self.create_read_seek(File::open(&path)?).await?; + let reader = self + .create_read_seek(File::open(&path)?, attr.is_compressed) + .await?; ctx.reader = Some(Box::new(reader)); ctx.attr = attr.into(); } @@ -2220,13 +2240,18 @@ impl EncryptedFs { if let Some(set_attr) = set_attr { self.set_attr(ino, set_attr).await?; } + let full_attr = self.get_inode_from_storage(ino).await?; + let writer = self - .create_write_seek(OpenOptions::new().read(true).write(true).open(&path)?) + .create_write_seek( + OpenOptions::new().read(true).write(true).open(&path)?, + full_attr.is_compressed, + ) .await?; + let mut ctx = lock.lock().await; ctx.writer = Some(Box::new(writer)); - let attr = self.get_inode_from_storage(ino).await?; - ctx.attr = attr.into(); + ctx.attr = full_attr.into(); } } @@ -2243,8 +2268,11 @@ impl EncryptedFs { let attr = self.get_inode_from_storage(ino).await?; match op { ReadHandleContextOperation::Create { ino } => { + let is_compressed = attr.is_compressed; let attr: TimesFileAttr = attr.into(); - let reader = self.create_read_seek(File::open(&path)?).await?; + let reader = self + .create_read_seek(File::open(&path)?, is_compressed) + .await?; let ctx = ReadHandleContext { ino, attr, @@ -2274,9 +2302,14 @@ impl EncryptedFs { let path = self.contents_path(ino); match op { WriteHandleContextOperation::Create { ino } => { - let attr = self.get_attr(ino).await?.into(); + let full_attr = self.get_attr(ino).await?; + let is_compressed_flag = full_attr.is_compressed; + let attr: TimesAndSizeFileAttr = full_attr.into(); let writer = self - .create_write_seek(OpenOptions::new().read(true).write(true).open(&path)?) + .create_write_seek( + OpenOptions::new().read(true).write(true).open(&path)?, + is_compressed_flag, + ) .await?; let ctx = WriteHandleContext { ino, @@ -2435,6 +2468,7 @@ impl EncryptedFs { File::open(path.clone())?, self.cipher, &*self.key.get().await?, + false, ))?; fs::remove_file(path)?; drop(guard); @@ -2521,7 +2555,7 @@ fn read_or_create_key( let derived_key = crypto::derive_key(password, cipher, &salt)?; if key_path.exists() { // read key - let reader = crypto::create_read(File::open(key_path)?, cipher, &derived_key); + let reader = crypto::create_read(File::open(key_path)?, cipher, &derived_key, false); let key: Vec = bincode::deserialize_from(reader).map_err(|_| FsError::InvalidPassword)?; Ok(SecretBox::new(Box::new(key))) @@ -2540,6 +2574,7 @@ fn read_or_create_key( .open(key_path)?, cipher, &derived_key, + false, ); bincode::serialize_into(&mut writer, &key)?; let file = writer.finish()?; diff --git a/src/lib.rs b/src/lib.rs index 22657c91..4c770ab6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -270,12 +270,12 @@ //! } //! //! let mut file = File::open(path_in.clone())?; -//! let mut writer = crypto::create_write(File::create(out.clone())?, cipher, &key); +//! let mut writer = crypto::create_write(File::create(out.clone())?, cipher, &key, false); //! info!("encrypt file"); //! io::copy(&mut file, &mut writer).unwrap(); //! writer.finish()?; //! -//! let mut reader = crypto::create_read(File::open(out)?, cipher, &key); +//! let mut reader = crypto::create_read(File::open(out)?, cipher, &key, false); //! info!("read file and compare hash to original one"); //! let hash1 = crypto::hash_reader(&mut File::open(path_in)?)?; //! let hash2 = crypto::hash_reader(&mut reader)?;