From 95db2e737acf4851250b6d833c77051d5b5bae2a Mon Sep 17 00:00:00 2001 From: Radu Marias Date: Sat, 4 May 2024 07:19:16 +0300 Subject: [PATCH] implement seek for reader --- examples/ring_crypto.rs | 2 +- src/crypto.rs | 33 ++++---- src/crypto/{decryptor.rs => reader.rs} | 73 +++++++++++++++--- src/crypto/{encryptor.rs => writer.rs} | 18 +++-- src/encryptedfs.rs | 101 +++++++++++-------------- src/encryptedfs/moved_test.rs | 22 +++--- src/stream_util.rs | 2 +- 7 files changed, 147 insertions(+), 104 deletions(-) rename src/crypto/{decryptor.rs => reader.rs} (53%) rename src/crypto/{encryptor.rs => writer.rs} (89%) diff --git a/examples/ring_crypto.rs b/examples/ring_crypto.rs index a46522ab..13bc8734 100644 --- a/examples/ring_crypto.rs +++ b/examples/ring_crypto.rs @@ -11,7 +11,7 @@ use tokio::fs; use rencfs::crypto; use rencfs::crypto::Cipher; -use rencfs::crypto::encryptor::CryptoWriter; +use rencfs::crypto::writer::CryptoWriter; use rencfs::encryptedfs::FsError; fn main() { diff --git a/src/crypto.rs b/src/crypto.rs index 16c955e7..ed17cfeb 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -3,6 +3,7 @@ use std::io::{Read, Write}; use std::io; use std::num::ParseIntError; use std::path::PathBuf; +use std::sync::Arc; use argon2::Argon2; use argon2::password_hash::rand_core::RngCore; @@ -18,13 +19,13 @@ use strum_macros::{Display, EnumIter, EnumString}; use thiserror::Error; use tracing::{debug, error, instrument}; -use crate::crypto::decryptor::{CryptoReader, RingCryptoReader}; -use crate::crypto::encryptor::{CryptoWriter, RingCryptoWriter}; +use crate::crypto::reader::{CryptoReader, RingCryptoReader}; +use crate::crypto::writer::{CryptoWriter, RingCryptoWriter}; use crate::encryptedfs::FsResult; use crate::stream_util; -pub mod decryptor; -pub mod encryptor; +pub mod reader; +pub mod writer; pub mod buf_mut; #[derive(Debug, Clone, EnumIter, EnumString, Display, Serialize, Deserialize, PartialEq)] @@ -75,24 +76,24 @@ pub enum Error { pub type Result = std::result::Result; -pub fn create_writer(writer: W, cipher: &Cipher, key: &SecretVec, nonce_seed: u64) -> impl CryptoWriter { +pub fn create_writer(writer: W, cipher: &Cipher, key: Arc>, nonce_seed: u64) -> impl CryptoWriter { create_ring_writer(writer, cipher, key, nonce_seed) } -fn create_ring_writer(writer: W, cipher: &Cipher, key: &SecretVec, nonce_seed: u64) -> RingCryptoWriter { +fn create_ring_writer(writer: W, cipher: &Cipher, key: Arc>, nonce_seed: u64) -> RingCryptoWriter { let algorithm = match cipher { Cipher::ChaCha20 => &CHACHA20_POLY1305, Cipher::Aes256Gcm => &AES_256_GCM, }; - RingCryptoWriter::new(writer, algorithm, &key.expose_secret(), nonce_seed) + RingCryptoWriter::new(writer, algorithm, key, nonce_seed) } -fn create_ring_reader(reader: R, cipher: &Cipher, key: &SecretVec, nonce_seed: u64) -> RingCryptoReader { +fn create_ring_reader(reader: R, cipher: &Cipher, key: Arc>, nonce_seed: u64) -> RingCryptoReader { let algorithm = match cipher { Cipher::ChaCha20 => &CHACHA20_POLY1305, Cipher::Aes256Gcm => &AES_256_GCM, }; - RingCryptoReader::new(reader, algorithm, &key.expose_secret(), nonce_seed) + RingCryptoReader::new(reader, algorithm, key, nonce_seed) } // fn _create_cryptostream_crypto_writer(mut file: File, cipher: &Cipher, key: &SecretVec) -> impl CryptoWriter { @@ -113,8 +114,8 @@ fn create_ring_reader(reader: R, cipher: &Cipher, key: &S // } #[instrument(skip(reader, key))] -pub fn create_reader(reader: R, cipher: &Cipher, key: &SecretVec, nonce_seed: u64) -> impl CryptoReader { - create_ring_reader(reader, cipher, &key, nonce_seed) +pub fn create_reader(reader: R, cipher: &Cipher, key: Arc>, nonce_seed: u64) -> impl CryptoReader { + create_ring_reader(reader, cipher, key, nonce_seed) } // fn _create_cryptostream_crypto_reader(mut file: File, cipher: &Cipher, key: &SecretVec) -> CryptostreamCryptoReader { @@ -140,7 +141,7 @@ pub fn create_reader(reader: R, cipher: &Cipher, key: &Se // CryptostreamCryptoReader::new(file, get_cipher(cipher), &key.expose_secret(), &iv).unwrap() // } -pub fn encrypt_string_with_nonce_seed(s: &SecretString, cipher: &Cipher, key: &SecretVec, nonce_seed: u64) -> Result { +pub fn encrypt_string_with_nonce_seed(s: &SecretString, cipher: &Cipher, key: Arc>, nonce_seed: u64) -> Result { let mut cursor = io::Cursor::new(vec![]); let mut writer = create_writer(cursor, cipher, key, nonce_seed); writer.write_all(s.expose_secret().as_bytes())?; @@ -150,7 +151,7 @@ pub fn encrypt_string_with_nonce_seed(s: &SecretString, cipher: &Cipher, key: &S Ok(format!("{}.{}", base64::encode(v), nonce_seed)) } -pub fn decrypt_string(s: &str, cipher: &Cipher, key: &SecretVec) -> Result { +pub fn decrypt_string(s: &str, cipher: &Cipher, key: Arc>) -> Result { // extract nonce seed if !s.contains(".") { return Err(Error::Generic("nonce seed is missing")); @@ -167,7 +168,7 @@ pub fn decrypt_string(s: &str, cipher: &Cipher, key: &SecretVec) -> Result) -> Result { +pub fn decrypt_file_name(name: &str, cipher: &Cipher, key: Arc>) -> Result { let name = String::from(name).replace("|", "/"); decrypt_string(&name, cipher, key) } @@ -185,7 +186,7 @@ pub fn derive_key(password: &SecretString, cipher: &Cipher, salt: SecretVec) Ok(SecretVec::new(dk)) } -pub fn encrypt_file_name_with_nonce_seed(name: &SecretString, cipher: &Cipher, key: &SecretVec, nonce_seed: u64) -> FsResult { +pub fn encrypt_file_name_with_nonce_seed(name: &SecretString, cipher: &Cipher, key: Arc>, nonce_seed: u64) -> FsResult { if name.expose_secret() != "$." && name.expose_secret() != "$.." { let normalized_name = SecretString::new(name.expose_secret().replace("/", " ").replace("\\", " ")); let mut encrypted = encrypt_string_with_nonce_seed(&normalized_name, cipher, key, nonce_seed)?; @@ -211,7 +212,7 @@ pub fn hash_secret(data: &SecretString) -> SecretVec { /// Copy from `pos` position in file `len` bytes #[instrument(skip(w, key), fields(pos = pos.to_formatted_string(& Locale::en), len = len.to_formatted_string(& Locale::en)))] -pub fn copy_from_file_exact(w: &mut impl Write, pos: u64, len: u64, cipher: &Cipher, key: &SecretVec, nonce_seed: u64, file: PathBuf) -> io::Result<()> { +pub fn copy_from_file_exact(w: &mut impl Write, pos: u64, len: u64, cipher: &Cipher, key: Arc>, nonce_seed: u64, file: PathBuf) -> io::Result<()> { debug!(""); if len == 0 { // no-op diff --git a/src/crypto/decryptor.rs b/src/crypto/reader.rs similarity index 53% rename from src/crypto/decryptor.rs rename to src/crypto/reader.rs index 67c9f0a0..2b6c51d9 100644 --- a/src/crypto/decryptor.rs +++ b/src/crypto/reader.rs @@ -1,11 +1,16 @@ -use std::io; +use std::{fs, io}; use std::io::{Read, Seek, SeekFrom}; +use std::sync::Arc; +use num_format::{Locale, ToFormattedString}; use ring::aead::{Aad, Algorithm, BoundKey, OpeningKey, UnboundKey}; -use tracing::{error, instrument}; +use secrecy::{ExposeSecret, SecretVec}; +use tracing::{debug, error, instrument}; use crate::crypto::buf_mut::BufMut; -use crate::crypto::encryptor::{BUF_SIZE, CounterNonceSequence}; +use crate::crypto::writer::{BUF_SIZE, CounterNonceSequence}; +use crate::encryptedfs::CONTENTS_DIR; +use crate::stream_util; pub trait CryptoReader: Read + Seek + Send + Sync { fn finish(&mut self) -> Option; @@ -47,21 +52,54 @@ pub trait CryptoReader: Read + Seek + Send + Sync { pub struct RingCryptoReader { input: Option, - opening_key: OpeningKey, + opening_key: Option>, buf: BufMut, + pos: u64, + algorithm: &'static Algorithm, + key: Arc>, + nonce_seed: u64, } impl RingCryptoReader { - pub fn new<'a: 'static>(r: R, algorithm: &'a Algorithm, key: &[u8], nonce_seed: u64) -> Self { - let unbound_key = UnboundKey::new(algorithm, &key).unwrap(); - let nonce_sequence = CounterNonceSequence::new(nonce_seed); - let opening_key = OpeningKey::new(unbound_key, nonce_sequence); + pub fn new(r: R, algorithm: &'static Algorithm, key: Arc>, nonce_seed: u64) -> Self { + let opening_key = Self::create_opening_key(algorithm, key.clone(), nonce_seed); let buf = BufMut::new(vec![0; BUF_SIZE + algorithm.tag_len()]); Self { input: Some(r), - opening_key, + opening_key: Some(opening_key), buf, + pos: 0, + algorithm, + key, + nonce_seed, + } + } + + fn create_opening_key(algorithm: &'static Algorithm, key: Arc>, nonce_seed: u64) -> OpeningKey { + let unbound_key = UnboundKey::new(algorithm, key.expose_secret()).unwrap(); + let nonce_sequence = CounterNonceSequence::new(nonce_seed); + OpeningKey::new(unbound_key, nonce_sequence) + } + + fn seek_from_start(&mut self, offset: u64) -> io::Result { + if self.pos != offset { + debug!("seeking to offset {} from {}", offset.to_formatted_string(&Locale::en), self.pos.to_formatted_string(&Locale::en)); + // in order to seek we need to read the bytes from current position until the offset + if self.pos > offset { + // if we need an offset before the current position, we can't seek back, we need + // to read from the beginning until the desired offset + debug!("seeking back, recreating decryptor"); + self.opening_key.replace(Self::create_opening_key(self.algorithm, self.key.clone(), self.nonce_seed)); + self.buf.clear(); + self.pos = 0; + } + debug!(pos = self.pos.to_formatted_string(&Locale::en), offset = offset.to_formatted_string(&Locale::en), "seeking"); + let len = offset - self.pos; + stream_util::read_seek_forward_exact(self, len)?; + self.pos += len; } + + Ok(self.pos) } } @@ -96,7 +134,7 @@ impl Read for RingCryptoReader { return Ok(0); } let mut data = &mut buffer[..len]; - let res = self.opening_key.open_within(Aad::empty(), &mut data, 0..); + let res = self.opening_key.as_mut().unwrap().open_within(Aad::empty(), &mut data, 0..); if res.is_err() { error!("error opening in place: {:?}", res); } @@ -105,13 +143,24 @@ impl Read for RingCryptoReader { }; self.buf.seek(SeekFrom::Start(pos as u64)).unwrap(); let len = self.buf.read(buf)?; + self.pos += len as u64; Ok(len) } } impl Seek for RingCryptoReader { - fn seek(&mut self, _pos: SeekFrom) -> io::Result { - todo!() + fn seek(&mut self, pos: SeekFrom) -> io::Result { + match pos { + SeekFrom::Start(pos) => self.seek_from_start(pos), + SeekFrom::End(_) => return Err(io::Error::new(io::ErrorKind::InvalidInput, "can't seek from end")), + SeekFrom::Current(pos) => { + let new_pos = self.pos as i64 + pos; + if new_pos < 0 { + return Err(io::Error::new(io::ErrorKind::InvalidInput, "can't seek before start")); + } + self.seek_from_start(new_pos as u64) + } + } } } diff --git a/src/crypto/encryptor.rs b/src/crypto/writer.rs similarity index 89% rename from src/crypto/encryptor.rs rename to src/crypto/writer.rs index 5d6a06a1..c2affecf 100644 --- a/src/crypto/encryptor.rs +++ b/src/crypto/writer.rs @@ -1,10 +1,12 @@ use std::io; use std::io::{BufWriter, Write}; +use std::sync::Arc; use rand_chacha::ChaCha8Rng; use rand_chacha::rand_core::{RngCore, SeedableRng}; use ring::aead::{Aad, Algorithm, BoundKey, Nonce, NONCE_LEN, NonceSequence, SealingKey, UnboundKey}; use ring::error::Unspecified; +use secrecy::{ExposeSecret, SecretVec}; use tracing::{error, instrument}; use crate::crypto::buf_mut::BufMut; @@ -57,9 +59,9 @@ pub struct RingCryptoWriter { } impl RingCryptoWriter { - pub fn new<'a: 'static>(w: W, algorithm: &'a Algorithm, key: &[u8], nonce_seed: u64) -> Self { + pub fn new<'a: 'static>(w: W, algorithm: &'a Algorithm, key: Arc>, nonce_seed: u64) -> Self { // todo: param for start nonce sequence - let unbound_key = UnboundKey::new(&algorithm, &key).unwrap(); + let unbound_key = UnboundKey::new(&algorithm, key.expose_secret()).unwrap(); let nonce_sequence = CounterNonceSequence::new(nonce_seed); let sealing_key = SealingKey::new(unbound_key, nonce_sequence); let buf = BufMut::new(vec![0; BUF_SIZE]); @@ -120,14 +122,16 @@ impl CryptoWriter for RingCryptoWriter { } } -pub(crate) struct CounterNonceSequence{ - rng: ChaCha8Rng, +pub(crate) struct CounterNonceSequence { + // rng: ChaCha8Rng, + seed: u64, } impl CounterNonceSequence { pub fn new(seed: u64) -> Self { Self { - rng: ChaCha8Rng::seed_from_u64(seed), + // rng: ChaCha8Rng::seed_from_u64(seed), + seed: 1, } } } @@ -137,9 +141,11 @@ impl NonceSequence for CounterNonceSequence { fn advance(&mut self) -> Result { let mut nonce_bytes = vec![0; NONCE_LEN]; - let bytes = self.rng.next_u64().to_le_bytes(); + // let bytes = self.rng.next_u64().to_le_bytes(); + let bytes = self.seed.to_le_bytes(); nonce_bytes[4..].copy_from_slice(&bytes); // println!("nonce_bytes = {}", hex::encode(&nonce_bytes)); + self.seed += 1; Nonce::try_assume_unique_for_key(&nonce_bytes) } diff --git a/src/encryptedfs.rs b/src/encryptedfs.rs index c7b6f450..564d1ad6 100644 --- a/src/encryptedfs.rs +++ b/src/encryptedfs.rs @@ -3,7 +3,7 @@ use std::cmp::max; use std::collections::{HashMap, HashSet}; use std::fmt::Debug; use std::fs::{File, OpenOptions, ReadDir}; -use std::io::{Read, Write}; +use std::io::{Read, Seek, SeekFrom, Write}; use std::num::ParseIntError; use std::ops::Deref; use std::path::PathBuf; @@ -27,8 +27,8 @@ use tracing::{debug, error, instrument, warn}; use crate::{crypto, stream_util}; use crate::arc_hashmap::{ArcHashMap, Guard}; use crate::crypto::{Cipher, extract_nonce_from_encrypted_string}; -use crate::crypto::decryptor::CryptoReader; -use crate::crypto::encryptor::CryptoWriter; +use crate::crypto::reader::CryptoReader; +use crate::crypto::writer::CryptoWriter; use crate::expire_value::{ExpireValue, Provider}; #[cfg(test)] @@ -400,7 +400,7 @@ impl Iterator for DirectoryEntryIterator { return Some(Err(FsError::from(err))); } nonce_seed = res.unwrap(); - crypto::decrypt_file_name(&name, &self.1, &self.2).map_err(|err| { + crypto::decrypt_file_name(&name, &self.1, self.2.clone()).map_err(|err| { error!(err = %err, "decrypting file name"); err }).ok() @@ -411,7 +411,7 @@ impl Iterator for DirectoryEntryIterator { } let name = name.unwrap(); - let res: bincode::Result<(u64, FileType)> = bincode::deserialize_from(crypto::create_reader(file, &self.1, &self.2, nonce_seed)); + let res: bincode::Result<(u64, FileType)> = bincode::deserialize_from(crypto::create_reader(file, &self.1, self.2.clone(), nonce_seed)); if let Err(e) = res { return Some(Err(e.into())); } @@ -482,7 +482,7 @@ impl Iterator for DirectoryEntryPlusIterator { return Some(Err(FsError::from(err))); } nonce_seed = res.unwrap(); - crypto::decrypt_file_name(&name, &self.2, &self.3).map_err(|err| { + crypto::decrypt_file_name(&name, &self.2, self.3.clone()).map_err(|err| { error!(err = %err, "decrypting file name"); err }).ok() @@ -493,7 +493,7 @@ impl Iterator for DirectoryEntryPlusIterator { } let name = name.unwrap(); - let res: bincode::Result<(u64, FileType)> = bincode::deserialize_from(crypto::create_reader(file, &self.2, &self.3, nonce_seed)); + let res: bincode::Result<(u64, FileType)> = bincode::deserialize_from(crypto::create_reader(file, &self.2, self.3.clone(), nonce_seed)); if let Err(e) = res { error!(err = %e, "deserializing directory entry"); return Some(Err(e.into())); @@ -510,7 +510,7 @@ impl Iterator for DirectoryEntryPlusIterator { return Some(Err(e.into())); } let file = file.unwrap(); - let attr = bincode::deserialize_from(crypto::create_reader(file, &self.2, &self.3, ino)); + let attr = bincode::deserialize_from(crypto::create_reader(file, &self.2, self.3.clone(), ino)); if let Err(e) = attr { error!(err = %e, "deserializing file attr"); return Some(Err(e.into())); @@ -711,7 +711,7 @@ impl EncryptedFs { attr.ino = self.generate_next_inode(); // write inode - self.write_inode_to_storage(&attr, &*self.key.get().await?).await?; + self.write_inode_to_storage(&attr, self.key.get().await?).await?; // create in contents directory match attr.kind { @@ -733,12 +733,12 @@ impl EncryptedFs { ino: attr.ino, name: SecretString::from_str("$.").unwrap(), kind: FileType::Directory, - }, &*self.key.get().await?, parent).await?; + }, self.key.get().await?, parent).await?; self.insert_directory_entry(attr.ino, DirectoryEntry { ino: parent, name: SecretString::from_str("$..").unwrap(), kind: FileType::Directory, - }, &*self.key.get().await?, parent).await?; + }, self.key.get().await?, parent).await?; } } @@ -747,7 +747,7 @@ impl EncryptedFs { ino: attr.ino, name: SecretString::new(name.expose_secret().to_owned()), kind: attr.kind, - }, &*self.key.get().await?, parent).await?; + }, self.key.get().await?, parent).await?; self.update_inode(parent, SetFileAttr::default() .with_mtime(SystemTime::now()) .with_ctime(SystemTime::now())).await?; @@ -786,7 +786,7 @@ impl EncryptedFs { SecretString::new(name.expose_secret().to_owned()) } }; - let name = crypto::encrypt_file_name_with_nonce_seed(&name, &self.cipher, &*self.key.get().await?, parent)?; + let name = crypto::encrypt_file_name_with_nonce_seed(&name, &self.cipher, self.key.get().await?, parent)?; let file = File::open(self.data_dir.join(CONTENTS_DIR).join(parent.to_string()).join(name))?; let (inode, _): (u64, FileType) = bincode::deserialize_from(self.create_crypto_reader(file, parent).await?)?; Ok(Some(self.get_inode(inode).await?)) @@ -885,7 +885,7 @@ impl EncryptedFs { SecretString::new(name.expose_secret().to_owned()) } }; - let name = crypto::encrypt_file_name_with_nonce_seed(&name, &self.cipher, &*self.key.get().await?, parent)?; + let name = crypto::encrypt_file_name_with_nonce_seed(&name, &self.cipher, self.key.get().await?, parent)?; Ok(self.data_dir.join(CONTENTS_DIR).join(parent.to_string()).join(name).exists()) } @@ -911,7 +911,7 @@ impl EncryptedFs { self.serialize_dir_entries_locks.clone(), self.serialize_inode_locks.clone())) } - async fn get_inode_from_storage(&self, ino: u64, key: &SecretVec) -> FsResult { + async fn get_inode_from_storage(&self, ino: u64, key: Arc>) -> FsResult { let map_guard = self.serialize_inode_locks.read().unwrap(); let lock = map_guard.get_or_insert_with(ino, || std::sync::RwLock::new(false)); let _guard = lock.read().unwrap(); @@ -923,7 +923,7 @@ impl EncryptedFs { pub async fn get_inode(&self, ino: u64) -> FsResult { debug!("get inode"); - let mut attr = self.get_inode_from_storage(ino, &*self.key.get().await?).await?; + let mut attr = self.get_inode_from_storage(ino, self.key.get().await?).await?; // merge time info and size with any open read handles let open_reads = { self.opened_files_for_read.read().await.contains_key(&ino) }; @@ -965,11 +965,11 @@ impl EncryptedFs { let mut attr = self.get_inode(ino).await?; merge_attr(&mut attr, set_attr); - self.write_inode_to_storage(&attr, &*self.key.get().await?).await?; + self.write_inode_to_storage(&attr, self.key.get().await?).await?; Ok(()) } - async fn write_inode_to_storage(&self, attr: &FileAttr, key: &SecretVec) -> Result<(), FsError> { + async fn write_inode_to_storage(&self, attr: &FileAttr, key: Arc>) -> Result<(), FsError> { let map = self.serialize_inode_locks.write().unwrap(); let lock = map.get_or_insert_with(attr.ino, || std::sync::RwLock::new(false)); let _guard = lock.write().unwrap(); @@ -1032,24 +1032,11 @@ impl EncryptedFs { return Ok(0); } - if ctx.pos != offset { - debug!("seeking to offset {} from {}", offset.to_formatted_string(&Locale::en), ctx.pos.to_formatted_string(&Locale::en)); - // in order to seek we need to read the bytes from current position until the offset - if ctx.pos > offset { - // if we need an offset before the current position, we can't seek back, we need - // to read from the beginning until the desired offset - debug!("seeking back, recreating reader"); - self.do_with_read_handle(handle, ReadHandleContextOperation::RecreateReader { existing: ctx }).await?; - ctx = guard.get(&handle).unwrap().lock().await; - } - let pos = ctx.pos; - let actual_file_size = fs::metadata(self.data_dir.join(CONTENTS_DIR).join(ino.to_string()))?.len(); - debug!(pos = pos.to_formatted_string(&Locale::en), offset = offset.to_formatted_string(&Locale::en), file_size = ctx.attr.size.to_formatted_string(&Locale::en), - actual_file_size = actual_file_size.to_formatted_string(&Locale::en), "seeking"); - let len = offset - pos; - stream_util::read_seek_forward_exact(&mut ctx.reader.as_mut().unwrap(), len)?; - ctx.pos += len; - } + ctx.reader.as_mut().unwrap().seek(SeekFrom::Start(offset)).map_err(|err| { + error!(err = %err, pos = ctx.pos.to_formatted_string(&Locale::en), offset = offset.to_formatted_string(&Locale::en), file_size = ctx.attr.size.to_formatted_string(&Locale::en), "seeking"); + err + })?; + if offset + buf.len() as u64 > ctx.attr.size { buf = &mut buf[..(ctx.attr.size - offset) as usize]; } @@ -1113,7 +1100,7 @@ impl EncryptedFs { let file_size = ctx.attr.size; let pos = ctx.pos; let len = file_size - pos; - crypto::copy_from_file_exact(&mut ctx.writer.as_mut().unwrap(), pos, len, &self.cipher, &*self.key.get().await?, ino, self.data_dir.join(CONTENTS_DIR).join(ino_str))?; + crypto::copy_from_file_exact(&mut ctx.writer.as_mut().unwrap(), pos, len, &self.cipher, self.key.get().await?, ino, self.data_dir.join(CONTENTS_DIR).join(ino_str))?; ctx.pos += len; } @@ -1228,7 +1215,7 @@ impl EncryptedFs { let ino_str = ino.to_string(); let offset_in_bounds = offset.min(size); let len = offset_in_bounds - pos; - crypto::copy_from_file_exact(&mut ctx.writer.as_mut().unwrap(), pos, len, &self.cipher, &*self.key.get().await?, ino, self.data_dir.join(CONTENTS_DIR).join(ino_str))?; + crypto::copy_from_file_exact(&mut ctx.writer.as_mut().unwrap(), pos, len, &self.cipher, self.key.get().await?, ino, self.data_dir.join(CONTENTS_DIR).join(ino_str))?; ctx.pos += len; } else { debug!("seeking backward or from the beginning of the file"); @@ -1244,7 +1231,7 @@ impl EncryptedFs { let guard = self.write_handles.read().await; let mut ctx = guard.get(&handle).unwrap().lock().await; let len = file_size - pos; - crypto::copy_from_file_exact(&mut ctx.writer.as_mut().unwrap(), pos, len, &self.cipher, &*self.key.get().await?, ino, self.data_dir.join(CONTENTS_DIR).join(ino_str))?; + crypto::copy_from_file_exact(&mut ctx.writer.as_mut().unwrap(), pos, len, &self.cipher, self.key.get().await?, ino, self.data_dir.join(CONTENTS_DIR).join(ino_str))?; ctx.pos += len; } { @@ -1287,7 +1274,7 @@ impl EncryptedFs { ctx.path = tmp_path; let ino_str = ctx.ino.to_string(); let offset_in_bounds = offset.min(size); - crypto::copy_from_file_exact(&mut ctx.writer.as_mut().unwrap(), 0, offset_in_bounds, &self.cipher, &*self.key.get().await?, ino, self.data_dir.join(CONTENTS_DIR).join(ino_str))?; + crypto::copy_from_file_exact(&mut ctx.writer.as_mut().unwrap(), 0, offset_in_bounds, &self.cipher, self.key.get().await?, ino, self.data_dir.join(CONTENTS_DIR).join(ino_str))?; ctx.pos += offset_in_bounds; } @@ -1510,7 +1497,7 @@ impl EncryptedFs { let file_size = ctx.attr.size; let pos = ctx.pos; let len = file_size - pos; - crypto::copy_from_file_exact(&mut ctx.writer.as_mut().unwrap(), pos, len, &self.cipher, &*self.key.get().await?, ino, self.data_dir.join(CONTENTS_DIR).join(ino_str))?; + crypto::copy_from_file_exact(&mut ctx.writer.as_mut().unwrap(), pos, len, &self.cipher, self.key.get().await?, ino, self.data_dir.join(CONTENTS_DIR).join(ino_str))?; ctx.pos += len; } } @@ -1580,7 +1567,7 @@ impl EncryptedFs { ino: attr.ino, name: SecretString::new(new_name.expose_secret().to_owned()), kind: attr.kind, - }, &*self.key.get().await?, new_parent).await?; + }, self.key.get().await?, new_parent).await?; let mut parent_attr = self.get_inode(parent).await?; parent_attr.mtime = SystemTime::now(); @@ -1598,7 +1585,7 @@ impl EncryptedFs { ino: new_parent, name: SecretString::from_str("$..").unwrap(), kind: FileType::Directory, - }, &*self.key.get().await?, parent).await?; + }, self.key.get().await?, parent).await?; } Ok(()) @@ -1606,17 +1593,17 @@ impl EncryptedFs { /// Create a crypto writer using internal encryption info. pub async fn create_crypto_writer(&self, file: File, nonce_seed: u64) -> FsResult> { - Ok(crypto::create_writer(file, &self.cipher, &*self.key.get().await?, nonce_seed)) + Ok(crypto::create_writer(file, &self.cipher, self.key.get().await?, nonce_seed)) } /// Create a crypto reader using internal encryption info. pub async fn create_crypto_reader(&self, file: File, nonce_seed: u64) -> FsResult> { - Ok(crypto::create_reader(file, &self.cipher, &*self.key.get().await?, nonce_seed)) + Ok(crypto::create_reader(file, &self.cipher, self.key.get().await?, nonce_seed)) } /// Decrypts a string using internal encryption info. pub async fn decrypt_string(&self, s: &str) -> FsResult { - Ok(crypto::decrypt_string(s, &self.cipher, &*self.key.get().await?)?) + Ok(crypto::decrypt_string(s, &self.cipher, self.key.get().await?)?) } /// Change the password of the filesystem used to access the encryption key. @@ -1629,7 +1616,7 @@ impl EncryptedFs { let salt = crypto::hash_secret(&old_password); 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_reader(File::open(enc_file.clone())?, &cipher, &initial_key, 42_u64); + let reader = crypto::create_reader(File::open(enc_file.clone())?, &cipher, Arc::new(initial_key), 42_u64); let key_store: KeyStore = bincode::deserialize_from(reader).map_err(|_| FsError::InvalidPassword)?; // check hash if key_store.hash != crypto::hash(key_store.key.expose_secret()) { @@ -1641,7 +1628,7 @@ impl EncryptedFs { let new_key = crypto::derive_key(&new_password, &cipher, salt)?; tokio::fs::remove_file(enc_file.clone()).await?; let mut writer = crypto::create_writer(OpenOptions::new().read(true).write(true).create(true).truncate(true).open(enc_file.clone())?, - &cipher, &new_key, 42_u64); + &cipher, Arc::new(new_key), 42_u64); bincode::serialize_into(&mut writer, &key_store)?; writer.flush()?; writer.finish()?; @@ -1698,7 +1685,7 @@ impl EncryptedFs { let path = self.data_dir.join(CONTENTS_DIR).join(ino.to_string()); let file = OpenOptions::new().read(true).write(true).open(path)?; let reader = self.create_crypto_reader(file, op.get_ino()).await?; - let attr = self.get_inode_from_storage(ino, &*self.key.get().await?).await?; + let attr = self.get_inode_from_storage(ino, self.key.get().await?).await?; match op { ReadHandleContextOperation::Create { ino, lock } => { let attr: TimeAndSizeFileAttr = attr.into(); @@ -1750,7 +1737,7 @@ impl EncryptedFs { existing.writer.replace(Box::new(writer)); existing.path = path.clone(); if reset_size { - let attr = self.get_inode_from_storage(ino, &*self.key.get().await?).await?; + let attr = self.get_inode_from_storage(ino, self.key.get().await?).await?; existing.attr.size = attr.size; debug!("resetting size to {}", attr.size.to_formatted_string(&Locale::en)); } @@ -1776,7 +1763,7 @@ impl EncryptedFs { attr.gid = libc::getgid(); } - self.write_inode_to_storage(&attr, &*self.key.get().await?).await?; + self.write_inode_to_storage(&attr, self.key.get().await?).await?; // create the directory tokio::fs::create_dir(self.data_dir.join(CONTENTS_DIR).join(attr.ino.to_string())).await?; @@ -1786,15 +1773,15 @@ impl EncryptedFs { ino: attr.ino, name: SecretString::from_str("$.").unwrap(), kind: FileType::Directory, - }, &*self.key.get().await?, ROOT_INODE).await?; + }, self.key.get().await?, ROOT_INODE).await?; } Ok(()) } - async fn insert_directory_entry(&self, parent: u64, entry: DirectoryEntry, key: &SecretVec, nonce_seed: u64) -> FsResult<()> { + async fn insert_directory_entry(&self, parent: u64, entry: DirectoryEntry, key: Arc>, nonce_seed: u64) -> FsResult<()> { let parent_path = self.data_dir.join(CONTENTS_DIR).join(parent.to_string()); - let name = crypto::encrypt_file_name_with_nonce_seed(&entry.name, &self.cipher, key, nonce_seed)?; + let name = crypto::encrypt_file_name_with_nonce_seed(&entry.name, &self.cipher, key.clone(), nonce_seed)?; let file_path = parent_path.join(name); let map = self.serialize_dir_entries_locks.write().unwrap(); @@ -1819,7 +1806,7 @@ impl EncryptedFs { async fn remove_directory_entry(&self, parent: u64, name: &SecretString) -> FsResult<()> { let parent_path = self.data_dir.join(CONTENTS_DIR).join(parent.to_string()); - let name = crypto::encrypt_file_name_with_nonce_seed(name, &self.cipher, &*self.key.get().await?, parent)?; + let name = crypto::encrypt_file_name_with_nonce_seed(name, &self.cipher, self.key.get().await?, parent)?; let file_path = parent_path.join(name); let map = self.serialize_dir_entries_locks.write().unwrap(); @@ -1852,7 +1839,7 @@ impl EncryptedFs { if path.exists() { // read key - let reader = crypto::create_reader(File::open(path)?, cipher, &derived_key, 42_u64); + let reader = crypto::create_reader(File::open(path)?, cipher, Arc::new(derived_key), 42_u64); let key_store: KeyStore = bincode::deserialize_from(reader).map_err(|_| FsError::InvalidPassword)?; // check hash if key_store.hash != crypto::hash(key_store.key.expose_secret()) { @@ -1872,7 +1859,7 @@ impl EncryptedFs { let key = SecretVec::new(key); let key_store = KeyStore::new(key); let mut writer = crypto::create_writer(OpenOptions::new().read(true).write(true).create(true).open(path)?, - cipher, &derived_key, 42_u64); + cipher, Arc::new(derived_key), 42_u64); bincode::serialize_into(&mut writer, &key_store)?; writer.flush()?; writer.finish()?; diff --git a/src/encryptedfs/moved_test.rs b/src/encryptedfs/moved_test.rs index 4b264842..adb8cd12 100644 --- a/src/encryptedfs/moved_test.rs +++ b/src/encryptedfs/moved_test.rs @@ -90,9 +90,9 @@ fn create_attr_from_type(kind: FileType) -> CreateFileAttr { } } -async fn read_to_string(path: PathBuf, fs: &EncryptedFs) -> String { +async fn read_to_string(path: PathBuf, fs: &EncryptedFs, ino: u64) -> String { let mut buf: Vec = vec![]; - fs.create_crypto_reader(OpenOptions::new().read(true).write(true).open(path).unwrap()).await.unwrap().read_to_end(&mut buf).unwrap(); + fs.create_crypto_reader(OpenOptions::new().read(true).write(true).open(path).unwrap(), ino).await.unwrap().read_to_end(&mut buf).unwrap(); String::from_utf8(buf).unwrap() } @@ -131,7 +131,7 @@ async fn test_write_all() { write_all_bytes_to_fs(&fs, attr.ino, 0, data.as_bytes(), fh).await.unwrap(); fs.flush(fh).await.unwrap(); fs.release(fh).await.unwrap(); - assert_eq!(data, read_to_string(fs.data_dir.join(CONTENTS_DIR).join(attr.ino.to_string()), &fs).await); + assert_eq!(data, read_to_string(fs.data_dir.join(CONTENTS_DIR).join(attr.ino.to_string()), &fs, attr.ino).await); let attr = fs.get_inode(attr.ino).await.unwrap(); assert_eq!(data.len() as u64, attr.size); @@ -141,7 +141,7 @@ async fn test_write_all() { write_all_bytes_to_fs(&fs, attr.ino, 5, data.as_bytes(), fh).await.unwrap(); fs.flush(fh).await.unwrap(); fs.release(fh).await.unwrap(); - assert_eq!(data, &read_to_string(fs.data_dir.join(CONTENTS_DIR).join(attr.ino.to_string()), &fs).await[5..]); + assert_eq!(data, &read_to_string(fs.data_dir.join(CONTENTS_DIR).join(attr.ino.to_string()), &fs, attr.ino).await[5..]); // offset after file end let data = "37"; @@ -149,7 +149,7 @@ async fn test_write_all() { write_all_bytes_to_fs(&fs, attr.ino, 42, data.as_bytes(), fh).await.unwrap(); fs.flush(fh).await.unwrap(); fs.release(fh).await.unwrap(); - assert_eq!(format!("test-37{}37", "\0".repeat(35)), read_to_string(fs.data_dir.join(CONTENTS_DIR).join(attr.ino.to_string()), &fs).await); + assert_eq!(format!("test-37{}37", "\0".repeat(35)), read_to_string(fs.data_dir.join(CONTENTS_DIR).join(attr.ino.to_string()), &fs, attr.ino).await); // offset before current position, several blocks let test_file_2 = SecretString::from_str("test-file-2").unwrap(); @@ -162,7 +162,7 @@ async fn test_write_all() { write_all_bytes_to_fs(&fs, attr.ino, 8, data2.as_bytes(), fh).await.unwrap(); fs.flush(fh).await.unwrap(); fs.release(fh).await.unwrap(); - assert_eq!("test-01-02-42", &read_to_string(fs.data_dir.join(CONTENTS_DIR).join(attr.ino.to_string()), &fs).await); + assert_eq!("test-01-02-42", &read_to_string(fs.data_dir.join(CONTENTS_DIR).join(attr.ino.to_string()), &fs, attr.ino).await); // write before current position then write to the end, also check it preserves the content from // the first write to offset to end of the file @@ -174,7 +174,7 @@ async fn test_write_all() { write_all_bytes_to_fs(&fs, attr.ino, data.len() as u64, b"-42", fh).await.unwrap(); fs.flush(fh).await.unwrap(); fs.release(fh).await.unwrap(); - let new_content = read_to_string(fs.data_dir.join(CONTENTS_DIR).join(attr.ino.to_string()), &fs).await; + let new_content = read_to_string(fs.data_dir.join(CONTENTS_DIR).join(attr.ino.to_string()), &fs, attr.ino).await; assert_eq!("test-37-37-42", new_content); let buf = [0; 0]; @@ -310,13 +310,13 @@ async fn test_truncate() { write_all_bytes_to_fs(&fs, attr.ino, 5, data.as_bytes(), fh).await.unwrap(); fs.truncate(attr.ino, 10).await.unwrap(); assert_eq!(10, fs.get_inode(attr.ino).await.unwrap().size); - assert_eq!(format!("test-37{}", "\0".repeat(3)), read_to_string(fs.data_dir.join(CONTENTS_DIR).join(attr.ino.to_string()), &fs).await); + assert_eq!(format!("test-37{}", "\0".repeat(3)), read_to_string(fs.data_dir.join(CONTENTS_DIR).join(attr.ino.to_string()), &fs, attr.ino).await); fs.release(fh).await.unwrap(); // size doesn't change fs.truncate(attr.ino, 10).await.unwrap(); assert_eq!(10, fs.get_inode(attr.ino).await.unwrap().size); - assert_eq!(format!("test-37{}", "\0".repeat(3)), read_to_string(fs.data_dir.join(CONTENTS_DIR).join(attr.ino.to_string()), &fs).await); + assert_eq!(format!("test-37{}", "\0".repeat(3)), read_to_string(fs.data_dir.join(CONTENTS_DIR).join(attr.ino.to_string()), &fs, attr.ino).await); // size decrease, preserve opened writer content let fh = fs.open(attr.ino, false, true).await.unwrap(); @@ -324,13 +324,13 @@ async fn test_truncate() { write_all_bytes_to_fs(&fs, attr.ino, 0, data.as_bytes(), fh).await.unwrap(); fs.truncate(attr.ino, 4).await.unwrap(); assert_eq!(4, fs.get_inode(attr.ino).await.unwrap().size); - assert_eq!("37st", read_to_string(fs.data_dir.join(CONTENTS_DIR).join(attr.ino.to_string()), &fs).await); + assert_eq!("37st", read_to_string(fs.data_dir.join(CONTENTS_DIR).join(attr.ino.to_string()), &fs, attr.ino).await); fs.release(fh).await.unwrap(); // size decrease to 0 fs.truncate(attr.ino, 0).await.unwrap(); assert_eq!(0, fs.get_inode(attr.ino).await.unwrap().size); - assert_eq!("".to_string(), read_to_string(fs.data_dir.join(CONTENTS_DIR).join(attr.ino.to_string()), &fs).await); + assert_eq!("".to_string(), read_to_string(fs.data_dir.join(CONTENTS_DIR).join(attr.ino.to_string()), &fs, attr.ino).await); }).await } diff --git a/src/stream_util.rs b/src/stream_util.rs index 611ad954..b64ee4ae 100644 --- a/src/stream_util.rs +++ b/src/stream_util.rs @@ -12,7 +12,7 @@ const BUF_SIZE: usize = 256 * 1024; const BUF_SIZE: usize = 1024 * 1024; // 1 MB buffer #[instrument(skip(r, len), fields(len = len.to_formatted_string( & Locale::en)))] -pub fn read_seek_forward_exact(mut r: impl Read, len: u64) -> io::Result<()> { +pub fn read_seek_forward_exact(r: &mut impl Read, len: u64) -> io::Result<()> { debug!(""); if len == 0 { return Ok(());