From d319b0641ebbd69102b7806e4aba78cf0c43dedd Mon Sep 17 00:00:00 2001 From: oupson Date: Tue, 31 May 2022 22:36:13 +0200 Subject: [PATCH 01/36] Add a linux lib for fuse filesystem --- Cargo.lock | 4 ++++ Cargo.toml | 3 ++- rustcryptfs-linux/Cargo.toml | 8 ++++++++ rustcryptfs-linux/src/lib.rs | 0 4 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 rustcryptfs-linux/Cargo.toml create mode 100644 rustcryptfs-linux/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 6d5298e..5d282e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -512,6 +512,10 @@ dependencies = [ "thiserror", ] +[[package]] +name = "rustcryptfs-linux" +version = "0.1.0" + [[package]] name = "ryu" version = "1.0.10" diff --git a/Cargo.toml b/Cargo.toml index b17d160..ae1d30a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = [ "rustcryptfs", - "rustcryptfs-lib" + "rustcryptfs-lib", + "rustcryptfs-linux" ] diff --git a/rustcryptfs-linux/Cargo.toml b/rustcryptfs-linux/Cargo.toml new file mode 100644 index 0000000..f528d7d --- /dev/null +++ b/rustcryptfs-linux/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rustcryptfs-linux" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/rustcryptfs-linux/src/lib.rs b/rustcryptfs-linux/src/lib.rs new file mode 100644 index 0000000..e69de29 From f8dba772753a8e1454b8ff2ca4fc41241c937547 Mon Sep 17 00:00:00 2001 From: oupson Date: Tue, 31 May 2022 22:56:36 +0200 Subject: [PATCH 02/36] Add basic filesystem structure on linux --- rustcryptfs-linux/Cargo.toml | 4 +++ rustcryptfs-linux/src/encrypted_filesystem.rs | 28 +++++++++++++++++++ rustcryptfs-linux/src/lib.rs | 3 ++ 3 files changed, 35 insertions(+) create mode 100644 rustcryptfs-linux/src/encrypted_filesystem.rs diff --git a/rustcryptfs-linux/Cargo.toml b/rustcryptfs-linux/Cargo.toml index f528d7d..45ed3c3 100644 --- a/rustcryptfs-linux/Cargo.toml +++ b/rustcryptfs-linux/Cargo.toml @@ -6,3 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +fuser = "0.11" +log = "0.4" +rustcryptfs-lib = { path = "../rustcryptfs-lib" } +thiserror = "1.0" \ No newline at end of file diff --git a/rustcryptfs-linux/src/encrypted_filesystem.rs b/rustcryptfs-linux/src/encrypted_filesystem.rs new file mode 100644 index 0000000..29941b4 --- /dev/null +++ b/rustcryptfs-linux/src/encrypted_filesystem.rs @@ -0,0 +1,28 @@ +use std::path::Path; + +use fuser::Filesystem; +use rustcryptfs_lib::config::CryptConf; + +pub struct EncryptedFs {} + +impl EncryptedFs { + pub fn new

(path: P) -> Self + where + P: AsRef, + { + todo!() + } + + pub fn new_from_config(config: &CryptConf) -> Self { + Self {} + } + + pub fn mount

(self, mountpoint: P) + where + P: AsRef, + { + fuser::mount2(self, mountpoint, &[]).unwrap(); + } +} + +impl Filesystem for EncryptedFs {} diff --git a/rustcryptfs-linux/src/lib.rs b/rustcryptfs-linux/src/lib.rs index e69de29..304a802 100644 --- a/rustcryptfs-linux/src/lib.rs +++ b/rustcryptfs-linux/src/lib.rs @@ -0,0 +1,3 @@ +mod encrypted_filesystem; + +pub use encrypted_filesystem::EncryptedFs; \ No newline at end of file From 8418d1795d9ead40a58c13fbbaeb2f2c47ee005f Mon Sep 17 00:00:00 2001 From: oupson Date: Tue, 31 May 2022 22:56:51 +0200 Subject: [PATCH 03/36] Add mount command on linux --- Cargo.lock | 100 ++++++++++++++++++++++++++++++++++++++++ rustcryptfs/Cargo.toml | 5 +- rustcryptfs/src/args.rs | 20 +++++++- rustcryptfs/src/main.rs | 18 +++++++- 4 files changed, 140 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5d282e3..6d5f73f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -116,6 +116,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + [[package]] name = "cfg-if" version = "1.0.0" @@ -241,6 +247,22 @@ dependencies = [ "termcolor", ] +[[package]] +name = "fuser" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "104ed58f182bc2975062cd3fab229e82b5762de420e26cf5645f661402694599" +dependencies = [ + "libc", + "log", + "memchr", + "page_size", + "pkg-config", + "smallvec", + "users", + "zerocopy", +] + [[package]] name = "generic-array" version = "0.14.5" @@ -382,6 +404,16 @@ version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "029d8d0b2f198229de29dca79676f2738ff952edf3fde542eb8bf94d8c21b435" +[[package]] +name = "page_size" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eebde548fbbf1ea81a99b128872779c437752fb99f217c45245e1a61dcd9edcd" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "password-hash" version = "0.3.2" @@ -402,6 +434,12 @@ dependencies = [ "digest", ] +[[package]] +name = "pkg-config" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" + [[package]] name = "polyval" version = "0.5.3" @@ -491,6 +529,7 @@ dependencies = [ "env_logger", "log", "rustcryptfs-lib", + "rustcryptfs-linux", "serde", "serde_json", ] @@ -515,6 +554,12 @@ dependencies = [ [[package]] name = "rustcryptfs-linux" version = "0.1.0" +dependencies = [ + "fuser", + "log", + "rustcryptfs-lib", + "thiserror", +] [[package]] name = "ryu" @@ -586,6 +631,12 @@ dependencies = [ "digest", ] +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + [[package]] name = "strsim" version = "0.10.0" @@ -609,6 +660,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + [[package]] name = "termcolor" version = "1.1.3" @@ -656,6 +719,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "universal-hash" version = "0.4.1" @@ -666,6 +735,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "users" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032" +dependencies = [ + "libc", + "log", +] + [[package]] name = "version_check" version = "0.9.4" @@ -708,3 +787,24 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "zerocopy" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "332f188cc1bcf1fe1064b8c58d150f497e697f49774aa846f2dc949d9a25f236" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0fbc82b82efe24da867ee52e015e58178684bd9dd64c34e66bdf21da2582a9f" +dependencies = [ + "proc-macro2", + "syn", + "synstructure", +] diff --git a/rustcryptfs/Cargo.toml b/rustcryptfs/Cargo.toml index 0d74ac6..4445f85 100644 --- a/rustcryptfs/Cargo.toml +++ b/rustcryptfs/Cargo.toml @@ -12,4 +12,7 @@ serde_json = "1.0.78" clap = { version = "3.1.18", features = ["derive"] } log = "0.4.17" rustcryptfs-lib = { path = "../rustcryptfs-lib" } -env_logger = "0.9.0" \ No newline at end of file +env_logger = "0.9.0" + +[target.'cfg(target_os = "linux")'.dependencies] +rustcryptfs-linux = { path = "../rustcryptfs-linux" } diff --git a/rustcryptfs/src/args.rs b/rustcryptfs/src/args.rs index b57bba8..44d66e5 100644 --- a/rustcryptfs/src/args.rs +++ b/rustcryptfs/src/args.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use clap::{Parser, Subcommand}; #[derive(Debug, Parser)] @@ -14,6 +16,9 @@ pub(crate) enum Commands { // List file contained in a directory Ls(LsCommand), + + /// Mount an encrypted folder + Mount(MountCommand), } #[derive(Debug, Parser)] @@ -42,4 +47,17 @@ pub(crate) struct LsCommand { /// The password #[clap(short, long)] pub(crate) password : Option -} \ No newline at end of file +} + +#[derive(Debug, Parser)] +pub(crate) struct MountCommand { + /// The directory + pub(crate) path: PathBuf, + + /// The mount point + pub(crate) mountpoint: PathBuf, + + /// The password + #[clap(short, long)] + pub(crate) password: Option, +} diff --git a/rustcryptfs/src/main.rs b/rustcryptfs/src/main.rs index a8e9b1a..49400bb 100644 --- a/rustcryptfs/src/main.rs +++ b/rustcryptfs/src/main.rs @@ -6,7 +6,7 @@ use std::{ use clap::Parser; -use args::{DecryptCommand, LsCommand}; +use args::{DecryptCommand, LsCommand, MountCommand}; use rustcryptfs_lib::GocryptFs; mod args; @@ -19,6 +19,7 @@ fn main() -> anyhow::Result<()> { match &args.command { args::Commands::Decrypt(c) => decrypt_file(c), args::Commands::Ls(c) => ls(c), + args::Commands::Mount(c) => mount(c), } } @@ -102,3 +103,18 @@ fn decrypt_file(c: &DecryptCommand) -> anyhow::Result<()> { Ok(()) } + +#[cfg(target_os = "linux")] +fn mount(mount: &MountCommand) -> anyhow::Result<()> { + use rustcryptfs_linux::EncryptedFs; + + let fs = EncryptedFs::new(&mount.path); + + fs.mount(&mount.mountpoint); + Ok(()) +} + +#[cfg(not(target_os = "linux"))] +fn mount(mount: &MountCommand) -> anyhow::Result<()> { + unimplemented!() +} From 6702757eaa3bb61d7c44ec4c91cacf8a2e2267b1 Mon Sep 17 00:00:00 2001 From: oupson Date: Tue, 31 May 2022 23:21:50 +0200 Subject: [PATCH 04/36] Get options for filesystem --- Cargo.lock | 1 + rustcryptfs-linux/Cargo.toml | 3 +- rustcryptfs-linux/src/encrypted_filesystem.rs | 32 ++++++++++++++----- rustcryptfs-linux/src/error.rs | 18 +++++++++++ rustcryptfs-linux/src/lib.rs | 1 + rustcryptfs/src/main.rs | 2 +- 6 files changed, 47 insertions(+), 10 deletions(-) create mode 100644 rustcryptfs-linux/src/error.rs diff --git a/Cargo.lock b/Cargo.lock index 6d5f73f..787dc4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -558,6 +558,7 @@ dependencies = [ "fuser", "log", "rustcryptfs-lib", + "serde_json", "thiserror", ] diff --git a/rustcryptfs-linux/Cargo.toml b/rustcryptfs-linux/Cargo.toml index 45ed3c3..4f9f09c 100644 --- a/rustcryptfs-linux/Cargo.toml +++ b/rustcryptfs-linux/Cargo.toml @@ -9,4 +9,5 @@ edition = "2021" fuser = "0.11" log = "0.4" rustcryptfs-lib = { path = "../rustcryptfs-lib" } -thiserror = "1.0" \ No newline at end of file +thiserror = "1.0" +serde_json = "1.0" \ No newline at end of file diff --git a/rustcryptfs-linux/src/encrypted_filesystem.rs b/rustcryptfs-linux/src/encrypted_filesystem.rs index 29941b4..e2ca24c 100644 --- a/rustcryptfs-linux/src/encrypted_filesystem.rs +++ b/rustcryptfs-linux/src/encrypted_filesystem.rs @@ -1,20 +1,36 @@ -use std::path::Path; +use std::{fs, path::Path}; use fuser::Filesystem; -use rustcryptfs_lib::config::CryptConf; +use rustcryptfs_lib::{config::CryptConf, filename::FilenameDecoder}; -pub struct EncryptedFs {} +use crate::error::Result; + +pub struct EncryptedFs { + master_key: Vec, + filename_decoder: FilenameDecoder, +} impl EncryptedFs { - pub fn new

(path: P) -> Self + pub fn new

(path: P, password: &str) -> Result where P: AsRef, { - todo!() - } + let path = path.as_ref(); - pub fn new_from_config(config: &CryptConf) -> Self { - Self {} + let conf_path = path.join("gocryptfs.conf"); + + let content = fs::read_to_string(conf_path)?; + + let conf: CryptConf = serde_json::from_str(&content)?; + + let master_key = conf.get_master_key(password.as_bytes())?; + + let filename_decoder = FilenameDecoder::new(&master_key)?; + + Ok(Self { + master_key, + filename_decoder, + }) } pub fn mount

(self, mountpoint: P) diff --git a/rustcryptfs-linux/src/error.rs b/rustcryptfs-linux/src/error.rs new file mode 100644 index 0000000..6e51870 --- /dev/null +++ b/rustcryptfs-linux/src/error.rs @@ -0,0 +1,18 @@ +use thiserror::Error; + +pub type Result = std::result::Result; + +#[derive(Debug, Error)] +pub enum Error { + #[error(transparent)] + IoError(#[from] std::io::Error), + + #[error(transparent)] + JsonError(#[from] serde_json::Error), + + #[error(transparent)] + RustCryptFsError(#[from] rustcryptfs_lib::error::Error), + + #[error(transparent)] + RustCryptFsFilenameError(#[from] rustcryptfs_lib::error::FilenameDecryptError), +} diff --git a/rustcryptfs-linux/src/lib.rs b/rustcryptfs-linux/src/lib.rs index 304a802..5d59b1c 100644 --- a/rustcryptfs-linux/src/lib.rs +++ b/rustcryptfs-linux/src/lib.rs @@ -1,3 +1,4 @@ mod encrypted_filesystem; +pub mod error; pub use encrypted_filesystem::EncryptedFs; \ No newline at end of file diff --git a/rustcryptfs/src/main.rs b/rustcryptfs/src/main.rs index 49400bb..86f6c46 100644 --- a/rustcryptfs/src/main.rs +++ b/rustcryptfs/src/main.rs @@ -108,7 +108,7 @@ fn decrypt_file(c: &DecryptCommand) -> anyhow::Result<()> { fn mount(mount: &MountCommand) -> anyhow::Result<()> { use rustcryptfs_linux::EncryptedFs; - let fs = EncryptedFs::new(&mount.path); + let fs = EncryptedFs::new(&mount.path, mount.password.as_ref().unwrap())?; fs.mount(&mount.mountpoint); Ok(()) From 75540ba718275842a202c5a4468112f1debddf72 Mon Sep 17 00:00:00 2001 From: oupson Date: Mon, 3 Oct 2022 14:47:39 +0200 Subject: [PATCH 05/36] Use GocryptFS in linux EncryptedFs --- rustcryptfs-linux/src/encrypted_filesystem.rs | 24 ++++--------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/rustcryptfs-linux/src/encrypted_filesystem.rs b/rustcryptfs-linux/src/encrypted_filesystem.rs index e2ca24c..2098494 100644 --- a/rustcryptfs-linux/src/encrypted_filesystem.rs +++ b/rustcryptfs-linux/src/encrypted_filesystem.rs @@ -1,13 +1,12 @@ -use std::{fs, path::Path}; +use std::path::Path; use fuser::Filesystem; -use rustcryptfs_lib::{config::CryptConf, filename::FilenameDecoder}; +use rustcryptfs_lib::GocryptFs; use crate::error::Result; pub struct EncryptedFs { - master_key: Vec, - filename_decoder: FilenameDecoder, + fs: GocryptFs, } impl EncryptedFs { @@ -15,22 +14,9 @@ impl EncryptedFs { where P: AsRef, { - let path = path.as_ref(); + let fs = GocryptFs::open(path, password)?; - let conf_path = path.join("gocryptfs.conf"); - - let content = fs::read_to_string(conf_path)?; - - let conf: CryptConf = serde_json::from_str(&content)?; - - let master_key = conf.get_master_key(password.as_bytes())?; - - let filename_decoder = FilenameDecoder::new(&master_key)?; - - Ok(Self { - master_key, - filename_decoder, - }) + Ok(Self { fs }) } pub fn mount

(self, mountpoint: P) From 057cefdb5c35712bc954cdf55b183adf21e1db2a Mon Sep 17 00:00:00 2001 From: oupson Date: Wed, 5 Oct 2022 11:15:47 +0200 Subject: [PATCH 06/36] Implemented a few fuse functions --- Cargo.lock | 5 +- .../src/filename/filename_encoded.rs | 22 +- rustcryptfs-lib/src/lib.rs | 2 +- rustcryptfs-linux/Cargo.toml | 3 +- rustcryptfs-linux/src/encrypted_filesystem.rs | 256 +++++++++++++++++- 5 files changed, 277 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 787dc4c..d86c2fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -373,9 +373,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.126" +version = "0.2.134" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb" [[package]] name = "log" @@ -556,6 +556,7 @@ name = "rustcryptfs-linux" version = "0.1.0" dependencies = [ "fuser", + "libc", "log", "rustcryptfs-lib", "serde_json", diff --git a/rustcryptfs-lib/src/filename/filename_encoded.rs b/rustcryptfs-lib/src/filename/filename_encoded.rs index 2edc65e..3d17c79 100644 --- a/rustcryptfs-lib/src/filename/filename_encoded.rs +++ b/rustcryptfs-lib/src/filename/filename_encoded.rs @@ -1,5 +1,7 @@ use std::path::Path; +use sha2::{Digest, Sha256}; + /// EncodedFilename #[derive(Debug, PartialEq)] pub enum EncodedFilename { @@ -14,13 +16,18 @@ impl EncodedFilename { { let path = file.as_ref(); - let filename = path.file_name().unwrap().to_str().expect("Failed to get filename"); + let filename = path + .file_name() + .unwrap() + .to_str() + .expect("Failed to get filename"); if filename.starts_with("gocryptfs.longname.") { if !filename.ends_with(".name") { let long = std::fs::read_to_string( path.parent().unwrap().join(format!("{}.name", filename)), - ).unwrap(); + ) + .unwrap(); Ok(EncodedFilename::LongFilename(LongFilename { filename: filename.to_string(), filename_content: long, @@ -43,7 +50,16 @@ pub struct LongFilename { impl From for EncodedFilename { fn from(filename: String) -> Self { if filename.len() > 255 { - unimplemented!() + let mut hasher = Sha256::new(); + hasher.update(filename.as_bytes()); + + Self::LongFilename(LongFilename { + filename: format!( + "gocryptfs.longname.{}.name", + base64::encode_config(hasher.finalize(), base64::URL_SAFE_NO_PAD) + ), + filename_content: filename, + }) } else { Self::ShortFilename(filename) } diff --git a/rustcryptfs-lib/src/lib.rs b/rustcryptfs-lib/src/lib.rs index 759ebc5..7aa6eca 100644 --- a/rustcryptfs-lib/src/lib.rs +++ b/rustcryptfs-lib/src/lib.rs @@ -45,7 +45,7 @@ impl GocryptFs { }) } - pub fn filename_decoder(&self) -> &FilenameDecoder { + pub fn filename_decoder<'s> (&'s self) -> &'s FilenameDecoder { &self.filename_decoder } diff --git a/rustcryptfs-linux/Cargo.toml b/rustcryptfs-linux/Cargo.toml index 4f9f09c..df25158 100644 --- a/rustcryptfs-linux/Cargo.toml +++ b/rustcryptfs-linux/Cargo.toml @@ -10,4 +10,5 @@ fuser = "0.11" log = "0.4" rustcryptfs-lib = { path = "../rustcryptfs-lib" } thiserror = "1.0" -serde_json = "1.0" \ No newline at end of file +serde_json = "1.0" +libc = "0.2" \ No newline at end of file diff --git a/rustcryptfs-linux/src/encrypted_filesystem.rs b/rustcryptfs-linux/src/encrypted_filesystem.rs index 2098494..c86ce9e 100644 --- a/rustcryptfs-linux/src/encrypted_filesystem.rs +++ b/rustcryptfs-linux/src/encrypted_filesystem.rs @@ -1,12 +1,26 @@ -use std::path::Path; +use std::{ + collections::BTreeMap, + ffi::OsStr, + fs::FileType as StdFileType, + os::unix::prelude::{FileTypeExt, MetadataExt, OsStrExt, PermissionsExt}, + path::{Path, PathBuf}, + sync::atomic::{AtomicU64, Ordering}, + time::{Duration, SystemTime}, +}; -use fuser::Filesystem; +use fuser::{FileAttr, FileType, Filesystem, FUSE_ROOT_ID}; use rustcryptfs_lib::GocryptFs; use crate::error::Result; +const BLOCK_SIZE: u64 = 4096; + +type InodeCache = BTreeMap; + pub struct EncryptedFs { fs: GocryptFs, + inode_cache: InodeCache, + file_handle: AtomicU64, } impl EncryptedFs { @@ -14,9 +28,21 @@ impl EncryptedFs { where P: AsRef, { + let path = path.as_ref(); + + log::info!("Opening dir ..."); let fs = GocryptFs::open(path, password)?; - Ok(Self { fs }) + log::info!("Done"); + + let mut inode_cache = BTreeMap::new(); + inode_cache.insert(FUSE_ROOT_ID, path.to_path_buf()); + + Ok(Self { + fs, + inode_cache, + file_handle: AtomicU64::new(0), + }) } pub fn mount

(self, mountpoint: P) @@ -25,6 +51,228 @@ impl EncryptedFs { { fuser::mount2(self, mountpoint, &[]).unwrap(); } + + fn get_path(&self, ino: u64) -> Option { + // TODO CHECK PERM + + // TODO AVOID CLONE + self.inode_cache.get(&ino).map(|p| p.clone()) + } + + fn get_real_size(size: u64) -> u64 { + let x = ((size as f64 - 48.0) / 4128.0).floor() as u64; + + x * 4096 + size - 48 - x * 4096 + } + + fn get_file_type(file_type: StdFileType) -> FileType { + if file_type.is_file() { + FileType::RegularFile + } else if file_type.is_dir() { + FileType::Directory + } else if file_type.is_symlink() { + FileType::Symlink + } else if file_type.is_socket() { + FileType::Socket + } else if file_type.is_char_device() { + FileType::CharDevice + } else if file_type.is_block_device() { + FileType::BlockDevice + } else if file_type.is_fifo() { + FileType::NamedPipe + } else { + unimplemented!() + } + } + + fn get_attr

(path: P, ino: u64) -> FileAttr + where + P: AsRef, + { + let meta = std::fs::metadata(&path).unwrap(); + + let file_type = Self::get_file_type(meta.file_type()); + + FileAttr { + ino, + size: EncryptedFs::get_real_size(meta.size()), + blocks: BLOCK_SIZE / meta.size(), + atime: meta.accessed().unwrap(), + mtime: meta.modified().unwrap(), + ctime: SystemTime::now(), //SystemTime::from(meta.ctime()), + crtime: SystemTime::now(), + kind: file_type, + perm: meta.permissions().mode() as u16, + nlink: meta.nlink() as u32, + uid: meta.uid(), + gid: meta.gid(), + rdev: meta.rdev() as u32, + blksize: meta.blksize() as u32, + flags: 0, + } + } } -impl Filesystem for EncryptedFs {} +trait InodeCacheExt { + fn get_or_insert_inode(&mut self, file_path: PathBuf) -> (u64, PathBuf); +} + +impl InodeCacheExt for InodeCache { + // TODO Try to avoid clone + fn get_or_insert_inode(&mut self, file_path: PathBuf) -> (u64, PathBuf) { + if let Some((ino, path)) = { + self.iter() + .find_map(|(i, p)| if p.eq(&file_path) { Some((i, p)) } else { None }) + } { + (*ino, path.clone()) + } else { + let ino = self.len() as u64 + 1; + self.insert(ino, file_path); + + (ino, self.get(&ino).unwrap().clone()) + } + } +} + +impl Filesystem for EncryptedFs { + fn access(&mut self, _req: &fuser::Request<'_>, ino: u64, mask: i32, reply: fuser::ReplyEmpty) { + log::debug!("access, ino : {}, mask : {}", ino, mask); + if let Some(path) = self.get_path(ino) { + reply.ok() + } else { + reply.error(libc::ENOENT) + } + } + + fn getattr(&mut self, _req: &fuser::Request<'_>, ino: u64, reply: fuser::ReplyAttr) { + log::debug!("getattr, ino : {}", ino); + if let Some(path) = self.get_path(ino) { + log::debug!("access, path = {:?}", path); + reply.attr(&Duration::new(0, 0), &Self::get_attr(path, ino)) + } else { + reply.error(libc::ENOENT) + } + } + + fn lookup( + &mut self, + _req: &fuser::Request<'_>, + parent: u64, + name: &std::ffi::OsStr, + reply: fuser::ReplyEntry, + ) { + if let Some(parent) = &self.get_path(parent) { + let iv = std::fs::read(parent.join("gocryptfs.diriv")).unwrap(); + let dir_decoder = self.fs.filename_decoder().get_decoder_for_dir(&iv); + + let encrypted_name = dir_decoder + .encrypt_filename(&name.to_string_lossy()) + .unwrap(); + + let encrypted_name = match encrypted_name { + rustcryptfs_lib::filename::EncodedFilename::ShortFilename(s) => s, + rustcryptfs_lib::filename::EncodedFilename::LongFilename(l) => l.filename, + }; + + let file_path = parent.join(encrypted_name); + + if file_path.exists() { + let (ino, file_path) = self.inode_cache.get_or_insert_inode(file_path); + + reply.entry(&Duration::new(0, 0), &Self::get_attr(file_path, ino), 0) + } else { + reply.error(libc::ENOENT) + } + } else { + reply.error(libc::ENOENT) + } + } + + fn opendir( + &mut self, + _req: &fuser::Request<'_>, + ino: u64, + _flags: i32, + reply: fuser::ReplyOpen, + ) { + let fh = self.file_handle.fetch_add(1, Ordering::SeqCst); + reply.opened(fh, 0); + } + + fn readdir( + &mut self, + _req: &fuser::Request<'_>, + ino: u64, + _fh: u64, + offset: i64, + mut reply: fuser::ReplyDirectory, + ) { + if let Some(folder_path) = &self.get_path(ino) { + log::debug!("folder_path :{:?}", folder_path); + + let iv = std::fs::read(folder_path.join("gocryptfs.diriv")).unwrap(); + + let dir_decoder = self.fs.filename_decoder().get_decoder_for_dir(&iv); + + for (index, (meta, encrypted_name, name)) in std::fs::read_dir(folder_path) + .unwrap() + .flat_map(|e| e.ok()) + .flat_map(|dir| extract_name(dir, folder_path, &dir_decoder)) + .skip(offset as usize) + .enumerate() + { + let (inode, _) = self + .inode_cache + .get_or_insert_inode(folder_path.join(&encrypted_name)); + + let file_type = Self::get_file_type(meta.file_type()); + + let buffer_full: bool = reply.add( + inode, + offset + index as i64 + 1, + file_type, + OsStr::from_bytes(name.as_bytes()), + ); + + if buffer_full { + break; + } + } + + reply.ok() + } else { + reply.error(libc::ENOENT) + } + } +} + +fn extract_name( + dir: std::fs::DirEntry, + folder_path: &PathBuf, + dir_decoder: &rustcryptfs_lib::filename::DirFilenameDecoder, +) -> Option<(std::fs::Metadata, String, String)> { + let filename = dir.file_name(); + let filename = filename.to_str().unwrap(); + if filename != "gocryptfs.conf" && filename != "gocryptfs.diriv" { + if filename.starts_with("gocryptfs.longname.") { + if !filename.ends_with(".name") { + let filename = + std::fs::read_to_string(folder_path.join(format!("{}.name", filename))) + .unwrap(); + dir_decoder + .decode_filename(filename.as_str()) + .map(|n| (dir.metadata().unwrap(), filename, n)) + .ok() + } else { + None + } + } else { + dir_decoder + .decode_filename(filename) + .map(|n| (dir.metadata().unwrap(), filename.to_string(), n)) + .ok() + } + } else { + None + } +} From c095d1e6dc6ba08ead11c5f645ffb53c959f3971 Mon Sep 17 00:00:00 2001 From: oupson Date: Wed, 5 Oct 2022 11:31:34 +0200 Subject: [PATCH 07/36] Fix bug with filename --- rustcryptfs-lib/src/filename/filename_encoded.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rustcryptfs-lib/src/filename/filename_encoded.rs b/rustcryptfs-lib/src/filename/filename_encoded.rs index 3d17c79..fdfd949 100644 --- a/rustcryptfs-lib/src/filename/filename_encoded.rs +++ b/rustcryptfs-lib/src/filename/filename_encoded.rs @@ -55,7 +55,7 @@ impl From for EncodedFilename { Self::LongFilename(LongFilename { filename: format!( - "gocryptfs.longname.{}.name", + "gocryptfs.longname.{}", base64::encode_config(hasher.finalize(), base64::URL_SAFE_NO_PAD) ), filename_content: filename, From c7d81087878b767ef84b5d8170585652bc6efa5c Mon Sep 17 00:00:00 2001 From: oupson Date: Thu, 6 Oct 2022 11:12:30 +0200 Subject: [PATCH 08/36] Fix get_real_size --- rustcryptfs-linux/src/encrypted_filesystem.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/rustcryptfs-linux/src/encrypted_filesystem.rs b/rustcryptfs-linux/src/encrypted_filesystem.rs index c86ce9e..d0cca84 100644 --- a/rustcryptfs-linux/src/encrypted_filesystem.rs +++ b/rustcryptfs-linux/src/encrypted_filesystem.rs @@ -60,9 +60,14 @@ impl EncryptedFs { } fn get_real_size(size: u64) -> u64 { - let x = ((size as f64 - 48.0) / 4128.0).floor() as u64; + if size == 0 { + 0 + } else { + let x = (size - 50) / 4128; - x * 4096 + size - 48 - x * 4096 + let y = (size - 50) - x * 4128; + x * 4096 + y + } } fn get_file_type(file_type: StdFileType) -> FileType { From 5cfbba8c9b470b792e42aa810defc367777b6f83 Mon Sep 17 00:00:00 2001 From: oupson Date: Thu, 6 Oct 2022 11:14:36 +0200 Subject: [PATCH 09/36] Fix get_attr --- rustcryptfs-linux/src/encrypted_filesystem.rs | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/rustcryptfs-linux/src/encrypted_filesystem.rs b/rustcryptfs-linux/src/encrypted_filesystem.rs index d0cca84..a6973ac 100644 --- a/rustcryptfs-linux/src/encrypted_filesystem.rs +++ b/rustcryptfs-linux/src/encrypted_filesystem.rs @@ -1,11 +1,10 @@ use std::{ collections::BTreeMap, ffi::OsStr, - fs::FileType as StdFileType, + ops::Add, os::unix::prelude::{FileTypeExt, MetadataExt, OsStrExt, PermissionsExt}, path::{Path, PathBuf}, - sync::atomic::{AtomicU64, Ordering}, - time::{Duration, SystemTime}, + time::{Duration, UNIX_EPOCH}, }; use fuser::{FileAttr, FileType, Filesystem, FUSE_ROOT_ID}; @@ -98,21 +97,27 @@ impl EncryptedFs { let file_type = Self::get_file_type(meta.file_type()); + let file_size = if meta.is_file() { + EncryptedFs::get_real_size(meta.size()) + } else { + meta.size() + }; + FileAttr { ino, - size: EncryptedFs::get_real_size(meta.size()), - blocks: BLOCK_SIZE / meta.size(), + size: file_size, + blocks: (file_size + BLOCK_SIZE - 1) / BLOCK_SIZE, atime: meta.accessed().unwrap(), mtime: meta.modified().unwrap(), - ctime: SystemTime::now(), //SystemTime::from(meta.ctime()), - crtime: SystemTime::now(), + ctime: UNIX_EPOCH.add(Duration::new(meta.ctime() as u64, 0)), + crtime: UNIX_EPOCH.add(Duration::new(meta.ctime() as u64, 0)), kind: file_type, perm: meta.permissions().mode() as u16, nlink: meta.nlink() as u32, uid: meta.uid(), gid: meta.gid(), - rdev: meta.rdev() as u32, - blksize: meta.blksize() as u32, + rdev: 0, + blksize: BLOCK_SIZE as u32, flags: 0, } } From 1ef3c1e477570a4f60dd1530ce0c3435eb7dfee7 Mon Sep 17 00:00:00 2001 From: oupson Date: Thu, 6 Oct 2022 11:57:19 +0200 Subject: [PATCH 10/36] Remove opendir --- rustcryptfs-linux/src/encrypted_filesystem.rs | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/rustcryptfs-linux/src/encrypted_filesystem.rs b/rustcryptfs-linux/src/encrypted_filesystem.rs index a6973ac..cea097d 100644 --- a/rustcryptfs-linux/src/encrypted_filesystem.rs +++ b/rustcryptfs-linux/src/encrypted_filesystem.rs @@ -19,7 +19,6 @@ type InodeCache = BTreeMap; pub struct EncryptedFs { fs: GocryptFs, inode_cache: InodeCache, - file_handle: AtomicU64, } impl EncryptedFs { @@ -37,11 +36,7 @@ impl EncryptedFs { let mut inode_cache = BTreeMap::new(); inode_cache.insert(FUSE_ROOT_ID, path.to_path_buf()); - Ok(Self { - fs, - inode_cache, - file_handle: AtomicU64::new(0), - }) + Ok(Self { fs, inode_cache }) } pub fn mount

(self, mountpoint: P) @@ -198,17 +193,6 @@ impl Filesystem for EncryptedFs { } } - fn opendir( - &mut self, - _req: &fuser::Request<'_>, - ino: u64, - _flags: i32, - reply: fuser::ReplyOpen, - ) { - let fh = self.file_handle.fetch_add(1, Ordering::SeqCst); - reply.opened(fh, 0); - } - fn readdir( &mut self, _req: &fuser::Request<'_>, From 608619eab67d15e6baa9f8b0eb39cb005ec7e805 Mon Sep 17 00:00:00 2001 From: oupson Date: Thu, 6 Oct 2022 11:58:50 +0200 Subject: [PATCH 11/36] Add . and .. in readdir of fuse fs --- rustcryptfs-linux/src/encrypted_filesystem.rs | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/rustcryptfs-linux/src/encrypted_filesystem.rs b/rustcryptfs-linux/src/encrypted_filesystem.rs index cea097d..d8bda21 100644 --- a/rustcryptfs-linux/src/encrypted_filesystem.rs +++ b/rustcryptfs-linux/src/encrypted_filesystem.rs @@ -202,12 +202,32 @@ impl Filesystem for EncryptedFs { mut reply: fuser::ReplyDirectory, ) { if let Some(folder_path) = &self.get_path(ino) { - log::debug!("folder_path :{:?}", folder_path); - let iv = std::fs::read(folder_path.join("gocryptfs.diriv")).unwrap(); let dir_decoder = self.fs.filename_decoder().get_decoder_for_dir(&iv); + if offset == 0 { + let ino_parent = if ino == FUSE_ROOT_ID { + FUSE_ROOT_ID + } else { + let parent = folder_path.parent().expect("Failed to get parent"); + self.inode_cache + .iter() + .find_map(|(ino, p)| if p == parent { Some(*ino) } else { None }) + .expect("Parent inode not found") + }; + + if !reply.add(ino, 1, FileType::Directory, ".") { + if reply.add(ino_parent, 2, FileType::Directory, "..") { + reply.ok(); + return; + } + } else { + reply.ok(); + return; + } + } + for (index, (meta, encrypted_name, name)) in std::fs::read_dir(folder_path) .unwrap() .flat_map(|e| e.ok()) @@ -223,7 +243,7 @@ impl Filesystem for EncryptedFs { let buffer_full: bool = reply.add( inode, - offset + index as i64 + 1, + offset + index as i64 + 1 + 2, file_type, OsStr::from_bytes(name.as_bytes()), ); From 520845131162c8aa3c8b9d1cfb41ff86a6011a19 Mon Sep 17 00:00:00 2001 From: oupson Date: Thu, 6 Oct 2022 11:59:22 +0200 Subject: [PATCH 12/36] Add read in fuse fs --- rustcryptfs-linux/src/encrypted_filesystem.rs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/rustcryptfs-linux/src/encrypted_filesystem.rs b/rustcryptfs-linux/src/encrypted_filesystem.rs index d8bda21..8711351 100644 --- a/rustcryptfs-linux/src/encrypted_filesystem.rs +++ b/rustcryptfs-linux/src/encrypted_filesystem.rs @@ -1,6 +1,8 @@ use std::{ collections::BTreeMap, ffi::OsStr, + fs::{File, FileType as StdFileType}, + io::{Read, Seek}, ops::Add, os::unix::prelude::{FileTypeExt, MetadataExt, OsStrExt, PermissionsExt}, path::{Path, PathBuf}, @@ -258,6 +260,44 @@ impl Filesystem for EncryptedFs { reply.error(libc::ENOENT) } } + + fn read( + &mut self, + _req: &fuser::Request<'_>, + ino: u64, + _fh: u64, + offset: i64, + _size: u32, + _flags: i32, + _lock_owner: Option, + reply: fuser::ReplyData, + ) { + if let Some(file_path) = &self.get_path(ino) { + log::debug!("read {:?}", file_path); + + let mut file = File::open(file_path).unwrap(); + let decoder = self.fs.content_decoder(); + + let mut buf = [0u8; 18]; + let n = file.read(&mut buf).unwrap(); + let id = if n < 18 { None } else { Some(&buf[2..]) }; + + let block_index = offset as u64 / 4096; + + let mut buf = [0u8; 4096 + 32]; + + file.seek(std::io::SeekFrom::Start(18 + block_index * (4096 + 32))) + .unwrap(); + + let n = file.read(&mut buf).unwrap(); + + let res = decoder.decrypt_block(&buf[..n], block_index, id).unwrap(); + + reply.data(&res); + } else { + reply.error(libc::ENOENT) + } + } } fn extract_name( From e86139986df6968e5ff3ef0443a1a9ca29b2a1e4 Mon Sep 17 00:00:00 2001 From: oupson Date: Thu, 6 Oct 2022 13:28:32 +0200 Subject: [PATCH 13/36] Remove useless login --- rustcryptfs-linux/src/encrypted_filesystem.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/rustcryptfs-linux/src/encrypted_filesystem.rs b/rustcryptfs-linux/src/encrypted_filesystem.rs index 8711351..04b8c85 100644 --- a/rustcryptfs-linux/src/encrypted_filesystem.rs +++ b/rustcryptfs-linux/src/encrypted_filesystem.rs @@ -143,7 +143,6 @@ impl InodeCacheExt for InodeCache { impl Filesystem for EncryptedFs { fn access(&mut self, _req: &fuser::Request<'_>, ino: u64, mask: i32, reply: fuser::ReplyEmpty) { - log::debug!("access, ino : {}, mask : {}", ino, mask); if let Some(path) = self.get_path(ino) { reply.ok() } else { @@ -152,9 +151,7 @@ impl Filesystem for EncryptedFs { } fn getattr(&mut self, _req: &fuser::Request<'_>, ino: u64, reply: fuser::ReplyAttr) { - log::debug!("getattr, ino : {}", ino); if let Some(path) = self.get_path(ino) { - log::debug!("access, path = {:?}", path); reply.attr(&Duration::new(0, 0), &Self::get_attr(path, ino)) } else { reply.error(libc::ENOENT) @@ -273,8 +270,6 @@ impl Filesystem for EncryptedFs { reply: fuser::ReplyData, ) { if let Some(file_path) = &self.get_path(ino) { - log::debug!("read {:?}", file_path); - let mut file = File::open(file_path).unwrap(); let decoder = self.fs.content_decoder(); From b5fbdb6fb0b4fb540cc6b223992239c932314366 Mon Sep 17 00:00:00 2001 From: oupson Date: Thu, 6 Oct 2022 15:08:02 +0200 Subject: [PATCH 14/36] Read more than 4096 bytes in read function --- rustcryptfs-linux/src/encrypted_filesystem.rs | 45 ++++++++++++++++--- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/rustcryptfs-linux/src/encrypted_filesystem.rs b/rustcryptfs-linux/src/encrypted_filesystem.rs index 04b8c85..2f8cdf7 100644 --- a/rustcryptfs-linux/src/encrypted_filesystem.rs +++ b/rustcryptfs-linux/src/encrypted_filesystem.rs @@ -2,7 +2,7 @@ use std::{ collections::BTreeMap, ffi::OsStr, fs::{File, FileType as StdFileType}, - io::{Read, Seek}, + io::{Read, Seek, SeekFrom}, ops::Add, os::unix::prelude::{FileTypeExt, MetadataExt, OsStrExt, PermissionsExt}, path::{Path, PathBuf}, @@ -264,7 +264,7 @@ impl Filesystem for EncryptedFs { ino: u64, _fh: u64, offset: i64, - _size: u32, + size: u32, _flags: i32, _lock_owner: Option, reply: fuser::ReplyData, @@ -277,18 +277,49 @@ impl Filesystem for EncryptedFs { let n = file.read(&mut buf).unwrap(); let id = if n < 18 { None } else { Some(&buf[2..]) }; - let block_index = offset as u64 / 4096; + let mut block_index = offset as u64 / 4096; + + let mut buffer = Vec::with_capacity(size as usize); + + let mut rem = size as usize; let mut buf = [0u8; 4096 + 32]; - file.seek(std::io::SeekFrom::Start(18 + block_index * (4096 + 32))) + file.seek(SeekFrom::Start(18 + block_index * (4096 + 32))) .unwrap(); - let n = file.read(&mut buf).unwrap(); + { + let n = file.read(&mut buf).unwrap(); - let res = decoder.decrypt_block(&buf[..n], block_index, id).unwrap(); + let res = decoder.decrypt_block(&buf[..n], block_index, id).unwrap(); - reply.data(&res); + let seek = (offset as u64 - block_index * 4096) as usize; + buffer.extend_from_slice(&res[seek..]); + + block_index += 1; + + rem -= res.len() - seek; + } + + while rem > 0 { + let n = file.read(&mut buf).unwrap(); + + if n == 0 { + break; + } + + let res = decoder.decrypt_block(&buf[..n], block_index, id).unwrap(); + + let size = res.len().min(rem); + + buffer.extend_from_slice(&res[..size]); + + block_index += 1; + + rem -= size; + } + + reply.data(&buffer); } else { reply.error(libc::ENOENT) } From 665cdd8b3745fd0f8abd813521fb7b40f7611a2d Mon Sep 17 00:00:00 2001 From: oupson Date: Thu, 6 Oct 2022 15:55:07 +0200 Subject: [PATCH 15/36] Prompt password --- Cargo.lock | 11 +++++++++++ rustcryptfs/Cargo.toml | 1 + rustcryptfs/src/main.rs | 25 ++++++++++++++++++++++--- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d86c2fc..6c681c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -520,6 +520,16 @@ version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" +[[package]] +name = "rpassword" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b763cb66df1c928432cc35053f8bd4cec3335d8559fc16010017d16b3c1680" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "rustcryptfs" version = "0.0.1" @@ -528,6 +538,7 @@ dependencies = [ "clap", "env_logger", "log", + "rpassword", "rustcryptfs-lib", "rustcryptfs-linux", "serde", diff --git a/rustcryptfs/Cargo.toml b/rustcryptfs/Cargo.toml index 4445f85..189b0bb 100644 --- a/rustcryptfs/Cargo.toml +++ b/rustcryptfs/Cargo.toml @@ -13,6 +13,7 @@ clap = { version = "3.1.18", features = ["derive"] } log = "0.4.17" rustcryptfs-lib = { path = "../rustcryptfs-lib" } env_logger = "0.9.0" +rpassword = "7.0.0" [target.'cfg(target_os = "linux")'.dependencies] rustcryptfs-linux = { path = "../rustcryptfs-linux" } diff --git a/rustcryptfs/src/main.rs b/rustcryptfs/src/main.rs index 86f6c46..a4660f9 100644 --- a/rustcryptfs/src/main.rs +++ b/rustcryptfs/src/main.rs @@ -26,12 +26,18 @@ fn main() -> anyhow::Result<()> { fn ls(c: &LsCommand) -> anyhow::Result<()> { let folder_path = Path::new(&c.folder_path); + let password = if let Some(password) = &c.password { + password.clone() + } else { + rpassword::prompt_password("Your password: ")? + }; + let fs = GocryptFs::open( c.gocryptfs_path .as_ref() .map(|p| Path::new(p)) .unwrap_or(folder_path), - c.password.as_ref().expect("Please input a password"), + &password, )?; let filename_decoder = fs.filename_decoder(); @@ -66,12 +72,19 @@ fn ls(c: &LsCommand) -> anyhow::Result<()> { fn decrypt_file(c: &DecryptCommand) -> anyhow::Result<()> { let file_path = Path::new(&c.file_path); + + let password = if let Some(password) = &c.password { + password.clone() + } else { + rpassword::prompt_password("Your password: ")? + }; + let fs = GocryptFs::open( c.gocryptfs_path .as_ref() .map(|p| Path::new(p)) .unwrap_or_else(|| file_path.parent().unwrap()), - c.password.as_ref().expect("Please input a password"), + &password, )?; let mut file = File::open(file_path).unwrap(); @@ -108,7 +121,13 @@ fn decrypt_file(c: &DecryptCommand) -> anyhow::Result<()> { fn mount(mount: &MountCommand) -> anyhow::Result<()> { use rustcryptfs_linux::EncryptedFs; - let fs = EncryptedFs::new(&mount.path, mount.password.as_ref().unwrap())?; + let password = if let Some(password) = &mount.password { + password.clone() + } else { + rpassword::prompt_password("Your password: ")? + }; + + let fs = EncryptedFs::new(&mount.path, &password)?; fs.mount(&mount.mountpoint); Ok(()) From 918f815a5b3023bfd7db2c164e08e1585461fe4c Mon Sep 17 00:00:00 2001 From: oupson Date: Thu, 6 Oct 2022 16:28:39 +0200 Subject: [PATCH 16/36] Work on Inode Cache --- rustcryptfs-linux/src/encrypted_filesystem.rs | 41 ++++--------------- rustcryptfs-linux/src/inode_cache.rs | 31 ++++++++++++++ rustcryptfs-linux/src/lib.rs | 2 + 3 files changed, 42 insertions(+), 32 deletions(-) create mode 100644 rustcryptfs-linux/src/inode_cache.rs diff --git a/rustcryptfs-linux/src/encrypted_filesystem.rs b/rustcryptfs-linux/src/encrypted_filesystem.rs index 2f8cdf7..7b340ce 100644 --- a/rustcryptfs-linux/src/encrypted_filesystem.rs +++ b/rustcryptfs-linux/src/encrypted_filesystem.rs @@ -12,12 +12,13 @@ use std::{ use fuser::{FileAttr, FileType, Filesystem, FUSE_ROOT_ID}; use rustcryptfs_lib::GocryptFs; -use crate::error::Result; +use crate::{ + error::Result, + inode_cache::{InodeCache, InodeCacheExt}, +}; const BLOCK_SIZE: u64 = 4096; -type InodeCache = BTreeMap; - pub struct EncryptedFs { fs: GocryptFs, inode_cache: InodeCache, @@ -48,13 +49,6 @@ impl EncryptedFs { fuser::mount2(self, mountpoint, &[]).unwrap(); } - fn get_path(&self, ino: u64) -> Option { - // TODO CHECK PERM - - // TODO AVOID CLONE - self.inode_cache.get(&ino).map(|p| p.clone()) - } - fn get_real_size(size: u64) -> u64 { if size == 0 { 0 @@ -86,6 +80,10 @@ impl EncryptedFs { } } + fn get_path(&self, ino: u64) -> Option<&PathBuf> { + self.inode_cache.get_path(ino) + } + fn get_attr

(path: P, ino: u64) -> FileAttr where P: AsRef, @@ -120,27 +118,6 @@ impl EncryptedFs { } } -trait InodeCacheExt { - fn get_or_insert_inode(&mut self, file_path: PathBuf) -> (u64, PathBuf); -} - -impl InodeCacheExt for InodeCache { - // TODO Try to avoid clone - fn get_or_insert_inode(&mut self, file_path: PathBuf) -> (u64, PathBuf) { - if let Some((ino, path)) = { - self.iter() - .find_map(|(i, p)| if p.eq(&file_path) { Some((i, p)) } else { None }) - } { - (*ino, path.clone()) - } else { - let ino = self.len() as u64 + 1; - self.insert(ino, file_path); - - (ino, self.get(&ino).unwrap().clone()) - } - } -} - impl Filesystem for EncryptedFs { fn access(&mut self, _req: &fuser::Request<'_>, ino: u64, mask: i32, reply: fuser::ReplyEmpty) { if let Some(path) = self.get_path(ino) { @@ -200,7 +177,7 @@ impl Filesystem for EncryptedFs { offset: i64, mut reply: fuser::ReplyDirectory, ) { - if let Some(folder_path) = &self.get_path(ino) { + if let Some(folder_path) = &self.inode_cache.get_path(ino).cloned() { let iv = std::fs::read(folder_path.join("gocryptfs.diriv")).unwrap(); let dir_decoder = self.fs.filename_decoder().get_decoder_for_dir(&iv); diff --git a/rustcryptfs-linux/src/inode_cache.rs b/rustcryptfs-linux/src/inode_cache.rs new file mode 100644 index 0000000..be91d95 --- /dev/null +++ b/rustcryptfs-linux/src/inode_cache.rs @@ -0,0 +1,31 @@ +use std::{collections::BTreeMap, path::PathBuf}; + +pub(crate) type InodeCache = BTreeMap; + +pub(crate) trait InodeCacheExt { + fn get_or_insert_inode(&mut self, file_path: PathBuf) -> (u64, PathBuf); + + fn get_path(&self, ino: u64) -> Option<&PathBuf>; +} + +impl InodeCacheExt for InodeCache { + // TODO Try to avoid clone + fn get_or_insert_inode(&mut self, file_path: PathBuf) -> (u64, PathBuf) { + if let Some((ino, path)) = + self.iter() + .find_map(|(i, p)| if p.eq(&file_path) { Some((i, p)) } else { None }) + { + (*ino, path.clone()) + } else { + let ino = self.len() as u64 + 1; + self.insert(ino, file_path); + + (ino, self.get(&ino).unwrap().clone()) + } + } + + fn get_path(&self, ino: u64) -> Option<&PathBuf> { + // TODO CHECK PERM + self.get(&ino) + } +} diff --git a/rustcryptfs-linux/src/lib.rs b/rustcryptfs-linux/src/lib.rs index 5d59b1c..8e1278d 100644 --- a/rustcryptfs-linux/src/lib.rs +++ b/rustcryptfs-linux/src/lib.rs @@ -1,4 +1,6 @@ mod encrypted_filesystem; +mod inode_cache; + pub mod error; pub use encrypted_filesystem::EncryptedFs; \ No newline at end of file From 77e78a51123baa27f123722c22c584d1b1fb559a Mon Sep 17 00:00:00 2001 From: oupson Date: Thu, 6 Oct 2022 16:29:09 +0200 Subject: [PATCH 17/36] Work on README --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 7271f11..61ef5ff 100644 --- a/README.md +++ b/README.md @@ -1 +1,10 @@ # RustCryptFS +An implementation of [gocryptfs](https://github.com/rfjakob/gocryptfs) in Rust. + +## Supported plaforms and features +- [x] Linux (via FUSE) + - [x] read + - [ ] write +- [ ] Windows + - [ ] read + - [ ] write \ No newline at end of file From 86eba12b5a0df3f8ea1baf378dea09ba1ec2eaaf Mon Sep 17 00:00:00 2001 From: oupson Date: Thu, 6 Oct 2022 17:00:16 +0200 Subject: [PATCH 18/36] Move get_real_size to rustcryptfs-lib --- rustcryptfs-lib/src/content_enc.rs | 29 +++++++++++++++++++ rustcryptfs-linux/src/encrypted_filesystem.rs | 15 ++-------- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/rustcryptfs-lib/src/content_enc.rs b/rustcryptfs-lib/src/content_enc.rs index ed94ff3..702bcbd 100644 --- a/rustcryptfs-lib/src/content_enc.rs +++ b/rustcryptfs-lib/src/content_enc.rs @@ -69,4 +69,33 @@ impl ContentEnc { return Ok(buf.to_vec()); } + + pub fn get_real_size(encrypted_size: u64) -> u64 { + if encrypted_size == 0 { + 0 + } else { + let x = (encrypted_size - 50) / 4128; + + let y = (encrypted_size - 50) - x * 4128; + x * 4096 + y + } + } +} + +#[cfg(test)] +mod test { + use super::ContentEnc; + + #[test] + fn test_get_real_size() { + assert_eq!(0, ContentEnc::get_real_size(0)); + + for real_size in 1..4096 * 4 + 1 { + let nbr_full_blocks = real_size / 4096; + let encrypted_size = + 18 + nbr_full_blocks * (4096 + 32) + real_size - nbr_full_blocks * 4096 + 32; + + assert_eq!(real_size, ContentEnc::get_real_size(encrypted_size)); + } + } } diff --git a/rustcryptfs-linux/src/encrypted_filesystem.rs b/rustcryptfs-linux/src/encrypted_filesystem.rs index 7b340ce..e858a88 100644 --- a/rustcryptfs-linux/src/encrypted_filesystem.rs +++ b/rustcryptfs-linux/src/encrypted_filesystem.rs @@ -10,7 +10,7 @@ use std::{ }; use fuser::{FileAttr, FileType, Filesystem, FUSE_ROOT_ID}; -use rustcryptfs_lib::GocryptFs; +use rustcryptfs_lib::{content_enc::ContentEnc, GocryptFs}; use crate::{ error::Result, @@ -49,17 +49,6 @@ impl EncryptedFs { fuser::mount2(self, mountpoint, &[]).unwrap(); } - fn get_real_size(size: u64) -> u64 { - if size == 0 { - 0 - } else { - let x = (size - 50) / 4128; - - let y = (size - 50) - x * 4128; - x * 4096 + y - } - } - fn get_file_type(file_type: StdFileType) -> FileType { if file_type.is_file() { FileType::RegularFile @@ -93,7 +82,7 @@ impl EncryptedFs { let file_type = Self::get_file_type(meta.file_type()); let file_size = if meta.is_file() { - EncryptedFs::get_real_size(meta.size()) + ContentEnc::get_real_size(meta.size()) } else { meta.size() }; From 53ece0c25712a7166448226e6ee6af7f3567e2f8 Mon Sep 17 00:00:00 2001 From: oupson Date: Thu, 6 Oct 2022 17:00:50 +0200 Subject: [PATCH 19/36] Add documentation for ContentEnc --- rustcryptfs-lib/src/content_enc.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/rustcryptfs-lib/src/content_enc.rs b/rustcryptfs-lib/src/content_enc.rs index 702bcbd..3bc902b 100644 --- a/rustcryptfs-lib/src/content_enc.rs +++ b/rustcryptfs-lib/src/content_enc.rs @@ -1,17 +1,21 @@ +//! Utilities for file encryption. + use aes_gcm::{aead::generic_array::GenericArray, aes::Aes256, AeadInPlace, AesGcm, NewAead}; use cipher::consts::{U16, U32}; use hkdf::Hkdf; -use crate::error::{Result, DecryptError}; +use crate::error::{DecryptError, Result}; type Aes256Gcm = AesGcm; +/// ContentEnc implement all methods related to file encryption. pub struct ContentEnc { key: GenericArray, iv_len: usize, } impl ContentEnc { + /// Init a new ContentEnc from the master key and the iv len. pub fn new(master_key: &[u8], iv_len: u8) -> Self { let mut key = [0u8; 32]; let hdkf = Hkdf::::new(None, &master_key); @@ -24,6 +28,7 @@ impl ContentEnc { } } + /// Decrypt a encrypted block of len (iv_len + decrypted_block_size + iv_len), with the block number and the file id. pub fn decrypt_block( &self, block: &[u8], @@ -70,6 +75,7 @@ impl ContentEnc { return Ok(buf.to_vec()); } + /// Return the decrypted size of a file, based on the encrypted size. pub fn get_real_size(encrypted_size: u64) -> u64 { if encrypted_size == 0 { 0 From fdc8aeaa53c33c97c8d871b80ee4b040ee96e213 Mon Sep 17 00:00:00 2001 From: oupson Date: Thu, 6 Oct 2022 17:06:34 +0200 Subject: [PATCH 20/36] Document GocryptFs --- rustcryptfs-lib/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rustcryptfs-lib/src/lib.rs b/rustcryptfs-lib/src/lib.rs index 7aa6eca..ff50e00 100644 --- a/rustcryptfs-lib/src/lib.rs +++ b/rustcryptfs-lib/src/lib.rs @@ -1,4 +1,4 @@ -//! A library to write gocryptfs compatible programs +//! A library to write gocryptfs compatible programs. use std::{fs::File, path::Path}; @@ -45,10 +45,12 @@ impl GocryptFs { }) } - pub fn filename_decoder<'s> (&'s self) -> &'s FilenameDecoder { + /// Get the [`filename decoder`](struct@FilenameDecoder) attached to this GocryptFs. + pub fn filename_decoder<'s>(&'s self) -> &'s FilenameDecoder { &self.filename_decoder } + /// Get the [`content decoder`](struct@ContentEnc) attached to this GocryptFs. pub fn content_decoder(&self) -> &ContentEnc { &self.content_decoder } From 4eb66cfad42067231d4c5c13850c30558ca0af76 Mon Sep 17 00:00:00 2001 From: oupson Date: Thu, 6 Oct 2022 17:07:37 +0200 Subject: [PATCH 21/36] Remove useless io mod --- rustcryptfs-lib/src/io/mod.rs | 155 ---------------------------------- 1 file changed, 155 deletions(-) delete mode 100644 rustcryptfs-lib/src/io/mod.rs diff --git a/rustcryptfs-lib/src/io/mod.rs b/rustcryptfs-lib/src/io/mod.rs deleted file mode 100644 index 5852394..0000000 --- a/rustcryptfs-lib/src/io/mod.rs +++ /dev/null @@ -1,155 +0,0 @@ -use std::{ - error::Error, - fs::File, - io::Read, - path::{Path, PathBuf}, -}; - -use crate::filename::{EncodedFilename, FilenameDecoder}; - -#[derive(Debug)] -pub struct DirCache { - filename: String, - dir_iv: [u8; 16], - dir_entries: Vec, -} - -impl DirCache { - pub fn load_from_path

(path: P) -> Self - where - P: AsRef, - { - let path = path.as_ref(); - - let mut dir_iv = [0u8; 16]; - { - let dir_iv_path = path.join("gocryptfs.diriv"); - - let mut file = File::open(dir_iv_path).unwrap(); - - file.read_exact(&mut dir_iv).unwrap(); - } - - let dir_entries = path - .read_dir() - .unwrap() - .filter_map(|f| { - if let Ok(entry) = f { - if entry.file_name() != "gocryptfs.conf" - && entry.file_name() != "gocryptfs.diriv" - { - Some(entry) - } else { - None - } - } else { - None - } - }) - .map(|f| DirEntry::try_from(f.path().as_path())) - .filter_map(|f| f.ok()) - .collect(); - - Self { - filename: path.to_string_lossy().to_string(), - dir_iv, - dir_entries, - } - } - - pub fn lookup

( - &self, - filename_decoder: &FilenameDecoder, - decrypted_path: P, - ) -> Option - where - P: AsRef, - { - let decrypted_path = decrypted_path.as_ref(); - - let mut components = decrypted_path.components(); - - let component = components.next().expect("lol"); - - let decoder = filename_decoder.get_decoder_for_dir(&self.dir_iv); - - let segment = decoder - .encrypt_filename(component.as_os_str().to_str().unwrap()) - .expect("lol"); - - let segment_path = match segment { - EncodedFilename::ShortFilename(filename) => PathBuf::from(filename), - EncodedFilename::LongFilename(long_filename) => PathBuf::from(long_filename.filename), - }; - - if segment_path.is_dir() { - let (size, _) = components.size_hint(); - - if size > 0 { - unimplemented!() - } else { - unimplemented!() - //None - } - } else { - // component.as_path() - unimplemented!() - }; - - } - - fn lookup_internal

( - &self, - filename_decoder: &FilenameDecoder, - decrypted_path: P, - dir: &DirCache, - ) -> Option - where - P: AsRef, - { - unimplemented!() - } -} - -#[derive(Debug)] -pub enum DirEntry { - Dir(DirCache), - File(String), -} - -impl DirEntry { - /// Returns `true` if the dir entry is [`Dir`]. - /// - /// [`Dir`]: DirEntry::Dir - #[must_use] - pub fn is_dir(&self) -> bool { - matches!(self, Self::Dir(..)) - } - - /// Returns `true` if the dir entry is [`File`]. - /// - /// [`File`]: DirEntry::File - #[must_use] - pub fn is_file(&self) -> bool { - matches!(self, Self::File(..)) - } -} - -impl TryFrom<&Path> for DirEntry { - type Error = Box; // TODO - - fn try_from(path: &Path) -> Result { - Ok(if path.is_dir() { - DirEntry::Dir(DirCache::load_from_path(path)) - } else { - DirEntry::File( - path.components() - .last() - .unwrap() - .as_os_str() - .to_string_lossy() - .to_string(), - ) - }) - } -} From 90f6a6db494900efe2459a989d6dab0e5424532b Mon Sep 17 00:00:00 2001 From: oupson Date: Fri, 7 Oct 2022 13:15:46 +0200 Subject: [PATCH 22/36] Move DirFilenameDecoder to his own file --- .../src/filename/dir_filename_decoder.rs | 49 +++++++++++++++++++ rustcryptfs-lib/src/filename/mod.rs | 49 ++----------------- 2 files changed, 52 insertions(+), 46 deletions(-) create mode 100644 rustcryptfs-lib/src/filename/dir_filename_decoder.rs diff --git a/rustcryptfs-lib/src/filename/dir_filename_decoder.rs b/rustcryptfs-lib/src/filename/dir_filename_decoder.rs new file mode 100644 index 0000000..8771be0 --- /dev/null +++ b/rustcryptfs-lib/src/filename/dir_filename_decoder.rs @@ -0,0 +1,49 @@ +use cipher::{block_padding::Pkcs7, inout::InOutBufReserved, Iv, Key, KeyIvInit}; +use crate::error::FilenameDecryptError; + +use super::{EmeCipher, EncodedFilename, IntoDecodable}; + +// TODO RENAME +pub struct DirFilenameDecoder<'a, 'b> { + filename_key: &'a Key, + iv: &'b Iv, +} + +impl<'a, 'b> DirFilenameDecoder<'a, 'b> { + pub fn new(filename_key: &'a Key, iv: &'b Iv) -> Self { + Self { filename_key, iv } + } + pub fn decode_filename(&self, name: S) -> Result + where + S: IntoDecodable, + { + let cipher = EmeCipher::new(self.filename_key, self.iv); + + let mut filename = base64::decode_config(name.to_decodable(), base64::URL_SAFE_NO_PAD)?; + let filename_decoded = cipher + .decrypt_padded_mut::(&mut filename) + .map_err(|_| FilenameDecryptError::DecryptError())?; + + Ok(String::from_utf8_lossy(filename_decoded).to_string()) + } + + pub fn encrypt_filename( + &self, + plain_text_name: &str, + ) -> Result { + let mut cipher = EmeCipher::new(self.filename_key, self.iv); + let mut res = [0u8; 2048]; + + let filename_encrypted = cipher + .encrypt_padded_inout_mut::( + InOutBufReserved::from_slices(plain_text_name.as_bytes(), &mut res).unwrap(), + ) + .map_err(|_| FilenameDecryptError::DecryptError())?; // TODO RENAME ERROR + + // TODO LONG FILENAME + + let filename = base64::encode_config(filename_encrypted, base64::URL_SAFE_NO_PAD); + + Ok(filename.into()) + } +} diff --git a/rustcryptfs-lib/src/filename/mod.rs b/rustcryptfs-lib/src/filename/mod.rs index 3492a13..8671625 100644 --- a/rustcryptfs-lib/src/filename/mod.rs +++ b/rustcryptfs-lib/src/filename/mod.rs @@ -7,8 +7,10 @@ use crate::error::FilenameDecryptError; pub(crate) type EmeCipher = DynamicEme; +mod dir_filename_decoder; mod filename_encoded; +pub use dir_filename_decoder::*; pub use filename_encoded::*; // TODO RENAME @@ -29,52 +31,7 @@ impl FilenameDecoder { pub fn get_decoder_for_dir<'a, 'b>(&'a self, iv: &'b [u8]) -> DirFilenameDecoder<'a, 'b> { let iv = Iv::::from_slice(iv); - DirFilenameDecoder { - filename_key: &self.filename_key, - iv, - } - } -} - -// TODO RENAME -pub struct DirFilenameDecoder<'a, 'b> { - filename_key: &'a Key, - iv: &'b Iv, -} - -impl<'a, 'b> DirFilenameDecoder<'a, 'b> { - pub fn decode_filename(&self, name: S) -> Result - where - S: IntoDecodable, - { - let cipher = EmeCipher::new(self.filename_key, self.iv); - - let mut filename = base64::decode_config(name.to_decodable(), base64::URL_SAFE_NO_PAD)?; - let filename_decoded = cipher - .decrypt_padded_mut::(&mut filename) - .map_err(|_| FilenameDecryptError::DecryptError())?; - - Ok(String::from_utf8_lossy(filename_decoded).to_string()) - } - - pub fn encrypt_filename( - &self, - plain_text_name: &str, - ) -> Result { - let mut cipher = EmeCipher::new(self.filename_key, self.iv); - let mut res = [0u8; 2048]; - - let filename_encrypted = cipher - .encrypt_padded_inout_mut::( - InOutBufReserved::from_slices(plain_text_name.as_bytes(), &mut res).unwrap(), - ) - .map_err(|_| FilenameDecryptError::DecryptError())?; // TODO RENAME ERROR - - // TODO LONG FILENAME - - let filename = base64::encode_config(filename_encrypted, base64::URL_SAFE_NO_PAD); - - Ok(filename.into()) + DirFilenameDecoder::new(&self.filename_key, iv) } } From fce791717cdee601deb3f183e3ac2b3f8cfe54d8 Mon Sep 17 00:00:00 2001 From: oupson Date: Fri, 7 Oct 2022 13:20:05 +0200 Subject: [PATCH 23/36] Remove useless serde_json error --- Cargo.lock | 1 - rustcryptfs-linux/Cargo.toml | 1 - rustcryptfs-linux/src/error.rs | 3 --- 3 files changed, 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c681c2..d1e2398 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -570,7 +570,6 @@ dependencies = [ "libc", "log", "rustcryptfs-lib", - "serde_json", "thiserror", ] diff --git a/rustcryptfs-linux/Cargo.toml b/rustcryptfs-linux/Cargo.toml index df25158..cbb3b6f 100644 --- a/rustcryptfs-linux/Cargo.toml +++ b/rustcryptfs-linux/Cargo.toml @@ -10,5 +10,4 @@ fuser = "0.11" log = "0.4" rustcryptfs-lib = { path = "../rustcryptfs-lib" } thiserror = "1.0" -serde_json = "1.0" libc = "0.2" \ No newline at end of file diff --git a/rustcryptfs-linux/src/error.rs b/rustcryptfs-linux/src/error.rs index 6e51870..c0215e7 100644 --- a/rustcryptfs-linux/src/error.rs +++ b/rustcryptfs-linux/src/error.rs @@ -7,9 +7,6 @@ pub enum Error { #[error(transparent)] IoError(#[from] std::io::Error), - #[error(transparent)] - JsonError(#[from] serde_json::Error), - #[error(transparent)] RustCryptFsError(#[from] rustcryptfs_lib::error::Error), From 733237ba404823e9db003616d25dc804be15f2eb Mon Sep 17 00:00:00 2001 From: oupson Date: Fri, 7 Oct 2022 20:51:56 +0200 Subject: [PATCH 24/36] Rename FilenameDecoder to FilenameCipher --- .../src/filename/dir_filename_decoder.rs | 49 ------------------- rustcryptfs-lib/src/filename/mod.rs | 25 +++++----- rustcryptfs-lib/src/lib.rs | 6 +-- rustcryptfs-linux/src/encrypted_filesystem.rs | 6 +-- rustcryptfs/src/main.rs | 2 +- 5 files changed, 19 insertions(+), 69 deletions(-) delete mode 100644 rustcryptfs-lib/src/filename/dir_filename_decoder.rs diff --git a/rustcryptfs-lib/src/filename/dir_filename_decoder.rs b/rustcryptfs-lib/src/filename/dir_filename_decoder.rs deleted file mode 100644 index 8771be0..0000000 --- a/rustcryptfs-lib/src/filename/dir_filename_decoder.rs +++ /dev/null @@ -1,49 +0,0 @@ -use cipher::{block_padding::Pkcs7, inout::InOutBufReserved, Iv, Key, KeyIvInit}; -use crate::error::FilenameDecryptError; - -use super::{EmeCipher, EncodedFilename, IntoDecodable}; - -// TODO RENAME -pub struct DirFilenameDecoder<'a, 'b> { - filename_key: &'a Key, - iv: &'b Iv, -} - -impl<'a, 'b> DirFilenameDecoder<'a, 'b> { - pub fn new(filename_key: &'a Key, iv: &'b Iv) -> Self { - Self { filename_key, iv } - } - pub fn decode_filename(&self, name: S) -> Result - where - S: IntoDecodable, - { - let cipher = EmeCipher::new(self.filename_key, self.iv); - - let mut filename = base64::decode_config(name.to_decodable(), base64::URL_SAFE_NO_PAD)?; - let filename_decoded = cipher - .decrypt_padded_mut::(&mut filename) - .map_err(|_| FilenameDecryptError::DecryptError())?; - - Ok(String::from_utf8_lossy(filename_decoded).to_string()) - } - - pub fn encrypt_filename( - &self, - plain_text_name: &str, - ) -> Result { - let mut cipher = EmeCipher::new(self.filename_key, self.iv); - let mut res = [0u8; 2048]; - - let filename_encrypted = cipher - .encrypt_padded_inout_mut::( - InOutBufReserved::from_slices(plain_text_name.as_bytes(), &mut res).unwrap(), - ) - .map_err(|_| FilenameDecryptError::DecryptError())?; // TODO RENAME ERROR - - // TODO LONG FILENAME - - let filename = base64::encode_config(filename_encrypted, base64::URL_SAFE_NO_PAD); - - Ok(filename.into()) - } -} diff --git a/rustcryptfs-lib/src/filename/mod.rs b/rustcryptfs-lib/src/filename/mod.rs index 8671625..d836f84 100644 --- a/rustcryptfs-lib/src/filename/mod.rs +++ b/rustcryptfs-lib/src/filename/mod.rs @@ -1,5 +1,5 @@ use aes::Aes256; -use cipher::{block_padding::Pkcs7, inout::InOutBufReserved, Iv, Key, KeyIvInit}; +use cipher::{Iv, Key}; use eme_mode::DynamicEme; use hkdf::Hkdf; @@ -7,18 +7,17 @@ use crate::error::FilenameDecryptError; pub(crate) type EmeCipher = DynamicEme; -mod dir_filename_decoder; +mod dir_filename_cipher; mod filename_encoded; -pub use dir_filename_decoder::*; +pub use dir_filename_cipher::*; pub use filename_encoded::*; -// TODO RENAME -pub struct FilenameDecoder { +pub struct FilenameCipher { filename_key: Key, } -impl FilenameDecoder { +impl FilenameCipher { pub fn new(master_key: &[u8]) -> Result { let mut key = [0u8; 32]; let hdkf = Hkdf::::new(None, &master_key); @@ -29,9 +28,9 @@ impl FilenameDecoder { }) } - pub fn get_decoder_for_dir<'a, 'b>(&'a self, iv: &'b [u8]) -> DirFilenameDecoder<'a, 'b> { + pub fn get_cipher_for_dir<'a, 'b>(&'a self, iv: &'b [u8]) -> DirFilenameCipher<'a, 'b> { let iv = Iv::::from_slice(iv); - DirFilenameDecoder::new(&self.filename_key, iv) + DirFilenameCipher::new(&self.filename_key, iv) } } @@ -39,15 +38,15 @@ impl FilenameDecoder { mod test { use crate::filename::EncodedFilename; - use super::FilenameDecoder; + use super::FilenameCipher; #[test] fn test_encrypt() { let master_key = base64::decode("9gtUW9XiiefEgEXEkbONI6rnUsd2yh5UZZLG0V8Bxgk=").unwrap(); let dir_iv = base64::decode("6ysCeWOp2euF1x39gth8KQ==").unwrap(); - let decoder = FilenameDecoder::new(&master_key).expect("Failed to get file decoder"); - let dir_decoder = decoder.get_decoder_for_dir(&dir_iv); + let decoder = FilenameCipher::new(&master_key).expect("Failed to get file decoder"); + let dir_decoder = decoder.get_cipher_for_dir(&dir_iv); let encoded = dir_decoder .encrypt_filename("7.mp4") @@ -64,8 +63,8 @@ mod test { let master_key = base64::decode("9gtUW9XiiefEgEXEkbONI6rnUsd2yh5UZZLG0V8Bxgk=").unwrap(); let dir_iv = base64::decode("6ysCeWOp2euF1x39gth8KQ==").unwrap(); - let decoder = FilenameDecoder::new(&master_key).expect("Failed to get file decoder"); - let dir_decoder = decoder.get_decoder_for_dir(&dir_iv); + let decoder = FilenameCipher::new(&master_key).expect("Failed to get file decoder"); + let dir_decoder = decoder.get_cipher_for_dir(&dir_iv); let decrypted = dir_decoder .decode_filename("vTBajRt-yCpxB7Sly0E7lQ") diff --git a/rustcryptfs-lib/src/lib.rs b/rustcryptfs-lib/src/lib.rs index ff50e00..56ea589 100644 --- a/rustcryptfs-lib/src/lib.rs +++ b/rustcryptfs-lib/src/lib.rs @@ -3,7 +3,7 @@ use std::{fs::File, path::Path}; use content_enc::ContentEnc; -use filename::FilenameDecoder; +use filename::FilenameCipher; pub mod config; pub mod content_enc; @@ -12,7 +12,7 @@ pub mod filename; /// A GocryptFs encrypted directory pub struct GocryptFs { - filename_decoder: FilenameDecoder, + filename_decoder: FilenameCipher, content_decoder: ContentEnc, } @@ -46,7 +46,7 @@ impl GocryptFs { } /// Get the [`filename decoder`](struct@FilenameDecoder) attached to this GocryptFs. - pub fn filename_decoder<'s>(&'s self) -> &'s FilenameDecoder { + pub fn filename_decoder<'s>(&'s self) -> &'s FilenameCipher { &self.filename_decoder } diff --git a/rustcryptfs-linux/src/encrypted_filesystem.rs b/rustcryptfs-linux/src/encrypted_filesystem.rs index e858a88..1837a74 100644 --- a/rustcryptfs-linux/src/encrypted_filesystem.rs +++ b/rustcryptfs-linux/src/encrypted_filesystem.rs @@ -133,7 +133,7 @@ impl Filesystem for EncryptedFs { ) { if let Some(parent) = &self.get_path(parent) { let iv = std::fs::read(parent.join("gocryptfs.diriv")).unwrap(); - let dir_decoder = self.fs.filename_decoder().get_decoder_for_dir(&iv); + let dir_decoder = self.fs.filename_decoder().get_cipher_for_dir(&iv); let encrypted_name = dir_decoder .encrypt_filename(&name.to_string_lossy()) @@ -169,7 +169,7 @@ impl Filesystem for EncryptedFs { if let Some(folder_path) = &self.inode_cache.get_path(ino).cloned() { let iv = std::fs::read(folder_path.join("gocryptfs.diriv")).unwrap(); - let dir_decoder = self.fs.filename_decoder().get_decoder_for_dir(&iv); + let dir_decoder = self.fs.filename_decoder().get_cipher_for_dir(&iv); if offset == 0 { let ino_parent = if ino == FUSE_ROOT_ID { @@ -295,7 +295,7 @@ impl Filesystem for EncryptedFs { fn extract_name( dir: std::fs::DirEntry, folder_path: &PathBuf, - dir_decoder: &rustcryptfs_lib::filename::DirFilenameDecoder, + dir_decoder: &rustcryptfs_lib::filename::DirFilenameCipher, ) -> Option<(std::fs::Metadata, String, String)> { let filename = dir.file_name(); let filename = filename.to_str().unwrap(); diff --git a/rustcryptfs/src/main.rs b/rustcryptfs/src/main.rs index a4660f9..57fe597 100644 --- a/rustcryptfs/src/main.rs +++ b/rustcryptfs/src/main.rs @@ -44,7 +44,7 @@ fn ls(c: &LsCommand) -> anyhow::Result<()> { let iv = std::fs::read(folder_path.join("gocryptfs.diriv"))?; - let dir_decoder = filename_decoder.get_decoder_for_dir(&iv); + let dir_decoder = filename_decoder.get_cipher_for_dir(&iv); for dir in std::fs::read_dir(folder_path)?.flat_map(|e| e.ok()) { let filename = dir.file_name(); From 2dabc7c0c079af36a32bc692aa9de7a840d338ed Mon Sep 17 00:00:00 2001 From: oupson Date: Fri, 7 Oct 2022 20:52:16 +0200 Subject: [PATCH 25/36] Add load_from_reader to GocryptFs --- rustcryptfs-lib/src/lib.rs | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/rustcryptfs-lib/src/lib.rs b/rustcryptfs-lib/src/lib.rs index 56ea589..e785bb2 100644 --- a/rustcryptfs-lib/src/lib.rs +++ b/rustcryptfs-lib/src/lib.rs @@ -1,6 +1,6 @@ //! A library to write gocryptfs compatible programs. -use std::{fs::File, path::Path}; +use std::{fs::File, io::Read, path::Path}; use content_enc::ContentEnc; use filename::FilenameCipher; @@ -26,17 +26,25 @@ impl GocryptFs { { let base_path = encrypted_dir_path.as_ref(); - let config = { - let mut config_file = - File::open(base_path.join("gocryptfs.conf")).expect("failed to get config"); + let mut config_file = + File::open(base_path.join("gocryptfs.conf")).expect("failed to get config"); - serde_json::from_reader::<_, config::CryptConf>(&mut config_file) - .expect("failed to parse config") - }; + Self::load_from_reader(&mut config_file, password.as_bytes()) + } - let master_key = config.get_master_key(password.as_bytes())?; + /// Load a gocryptfs from the config. + /// + /// reader_config must be a reader of a valid `gocryptfs.conf`. + pub fn load_from_reader(reader_config: &mut R, password: &[u8]) -> error::Result + where + R: Read, + { + let config = serde_json::from_reader::<_, config::CryptConf>(reader_config) + .expect("failed to parse config"); - let filename_decoder = FilenameDecoder::new(&master_key)?; + let master_key = config.get_master_key(password)?; + + let filename_decoder = FilenameCipher::new(&master_key)?; let content_decoder = ContentEnc::new(&master_key, 16); // TODO IV LEN Ok(Self { From 965c07df0a2286c069c362b9db5f9b2b3a69baff Mon Sep 17 00:00:00 2001 From: oupson Date: Fri, 7 Oct 2022 20:55:56 +0200 Subject: [PATCH 26/36] Rename content_enc to content --- .../src/{content_enc.rs => content.rs} | 0 .../src/filename/dir_filename_cipher.rs | 49 +++++++++++++++++++ rustcryptfs-lib/src/lib.rs | 4 +- rustcryptfs-linux/src/encrypted_filesystem.rs | 2 +- 4 files changed, 52 insertions(+), 3 deletions(-) rename rustcryptfs-lib/src/{content_enc.rs => content.rs} (100%) create mode 100644 rustcryptfs-lib/src/filename/dir_filename_cipher.rs diff --git a/rustcryptfs-lib/src/content_enc.rs b/rustcryptfs-lib/src/content.rs similarity index 100% rename from rustcryptfs-lib/src/content_enc.rs rename to rustcryptfs-lib/src/content.rs diff --git a/rustcryptfs-lib/src/filename/dir_filename_cipher.rs b/rustcryptfs-lib/src/filename/dir_filename_cipher.rs new file mode 100644 index 0000000..deb102a --- /dev/null +++ b/rustcryptfs-lib/src/filename/dir_filename_cipher.rs @@ -0,0 +1,49 @@ +use crate::error::FilenameDecryptError; +use cipher::{block_padding::Pkcs7, inout::InOutBufReserved, Iv, Key, KeyIvInit}; + +use super::{EmeCipher, EncodedFilename, IntoDecodable}; + +pub struct DirFilenameCipher<'a, 'b> { + filename_key: &'a Key, + iv: &'b Iv, +} + +impl<'a, 'b> DirFilenameCipher<'a, 'b> { + pub fn new(filename_key: &'a Key, iv: &'b Iv) -> Self { + Self { filename_key, iv } + } + + pub fn decode_filename(&self, name: S) -> Result + where + S: IntoDecodable, + { + let cipher = EmeCipher::new(self.filename_key, self.iv); + + let mut filename = base64::decode_config(name.to_decodable(), base64::URL_SAFE_NO_PAD)?; + let filename_decoded = cipher + .decrypt_padded_mut::(&mut filename) + .map_err(|_| FilenameDecryptError::DecryptError())?; + + Ok(String::from_utf8_lossy(filename_decoded).to_string()) + } + + pub fn encrypt_filename( + &self, + plain_text_name: &str, + ) -> Result { + let mut cipher = EmeCipher::new(self.filename_key, self.iv); + let mut res = [0u8; 2048]; + + let filename_encrypted = cipher + .encrypt_padded_inout_mut::( + InOutBufReserved::from_slices(plain_text_name.as_bytes(), &mut res).unwrap(), + ) + .map_err(|_| FilenameDecryptError::DecryptError())?; // TODO RENAME ERROR + + // TODO LONG FILENAME + + let filename = base64::encode_config(filename_encrypted, base64::URL_SAFE_NO_PAD); + + Ok(filename.into()) + } +} diff --git a/rustcryptfs-lib/src/lib.rs b/rustcryptfs-lib/src/lib.rs index e785bb2..e46bf4e 100644 --- a/rustcryptfs-lib/src/lib.rs +++ b/rustcryptfs-lib/src/lib.rs @@ -2,11 +2,11 @@ use std::{fs::File, io::Read, path::Path}; -use content_enc::ContentEnc; +use content::ContentEnc; use filename::FilenameCipher; pub mod config; -pub mod content_enc; +pub mod content; pub mod error; pub mod filename; diff --git a/rustcryptfs-linux/src/encrypted_filesystem.rs b/rustcryptfs-linux/src/encrypted_filesystem.rs index 1837a74..3331375 100644 --- a/rustcryptfs-linux/src/encrypted_filesystem.rs +++ b/rustcryptfs-linux/src/encrypted_filesystem.rs @@ -10,7 +10,7 @@ use std::{ }; use fuser::{FileAttr, FileType, Filesystem, FUSE_ROOT_ID}; -use rustcryptfs_lib::{content_enc::ContentEnc, GocryptFs}; +use rustcryptfs_lib::{content::ContentEnc, GocryptFs}; use crate::{ error::Result, From c57f9b3a858a0230da3945a5e8b9cd83af33a532 Mon Sep 17 00:00:00 2001 From: oupson Date: Sat, 8 Oct 2022 16:10:43 +0200 Subject: [PATCH 27/36] Error related rustcryptfs-lib refracto --- rustcryptfs-lib/src/config/error.rs | 29 +++++++++++ .../src/{config.rs => config/mod.rs} | 21 ++++---- rustcryptfs-lib/src/content/error.rs | 19 ++++++++ .../src/{content.rs => content/mod.rs} | 19 ++++---- rustcryptfs-lib/src/error.rs | 48 ++++--------------- .../src/filename/dir_filename_cipher.rs | 19 +++----- rustcryptfs-lib/src/filename/error.rs | 13 +++++ rustcryptfs-lib/src/filename/mod.rs | 6 +-- rustcryptfs-lib/src/lib.rs | 7 ++- rustcryptfs-linux/src/error.rs | 3 +- 10 files changed, 105 insertions(+), 79 deletions(-) create mode 100644 rustcryptfs-lib/src/config/error.rs rename rustcryptfs-lib/src/{config.rs => config/mod.rs} (90%) create mode 100644 rustcryptfs-lib/src/content/error.rs rename rustcryptfs-lib/src/{content.rs => content/mod.rs} (89%) create mode 100644 rustcryptfs-lib/src/filename/error.rs diff --git a/rustcryptfs-lib/src/config/error.rs b/rustcryptfs-lib/src/config/error.rs new file mode 100644 index 0000000..17fdadc --- /dev/null +++ b/rustcryptfs-lib/src/config/error.rs @@ -0,0 +1,29 @@ +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum ConfigError { + #[error(transparent)] + ScryptError(#[from] ScryptError), + #[error(transparent)] + HdkfError(#[from] hkdf::InvalidLength), + #[error("Failed to decode base64")] + Base64Error(#[from] base64::DecodeError), + #[error("Failed to decrypt master key")] + MasterKeyDecryptError(), + #[error("Invalid master key length")] + InvalidMasterKeyLengthError(), +} + +impl From for ConfigError { + fn from(_: aes_gcm::Error) -> Self { + Self::MasterKeyDecryptError() + } +} + +#[derive(Debug, Error)] +pub enum ScryptError { + #[error(transparent)] + InvalidParams(#[from] scrypt::errors::InvalidParams), + #[error(transparent)] + InvalidOutputLen(#[from] scrypt::errors::InvalidOutputLen), +} diff --git a/rustcryptfs-lib/src/config.rs b/rustcryptfs-lib/src/config/mod.rs similarity index 90% rename from rustcryptfs-lib/src/config.rs rename to rustcryptfs-lib/src/config/mod.rs index 97b2f2e..e8ea895 100644 --- a/rustcryptfs-lib/src/config.rs +++ b/rustcryptfs-lib/src/config/mod.rs @@ -9,7 +9,9 @@ use aes_gcm::{ }; use hkdf::Hkdf; -use crate::error::{FilenameDecryptError, Result, ScryptError}; +mod error; + +pub use error::*; /// An enum that contain all the feature flag a gocryptfs config can have. #[derive(serde::Deserialize, Debug, PartialEq, Eq, Hash)] @@ -69,7 +71,7 @@ impl CryptConf { /// See gocryptfs documentation about [master key](https://nuetzlich.net/gocryptfs/forward_mode_crypto/#master-key-storage). /// /// ![TODO NAME THIS IMAGE](https://nuetzlich.net/gocryptfs/img/master-key.svg) - pub fn get_master_key(&self, password: &[u8]) -> Result<[u8; 32]> { + pub fn get_master_key(&self, password: &[u8]) -> Result<[u8; 32], ConfigError> { let block = base64::decode(&self.encrypted_key)?; let key = self.scrypt_object.get_hkdf_key(password)?; @@ -77,7 +79,9 @@ impl CryptConf { let tag = &block[block.len() - 16..]; let ciphertext = &block[16..block.len() - 16]; - let mut buf: [u8; 32] = ciphertext.try_into().expect("TODO"); + let mut buf: [u8; 32] = ciphertext + .try_into() + .map_err(|_| ConfigError::InvalidMasterKeyLengthError())?; let aes = AesGcm::::new(Key::from_slice(&key)); @@ -133,19 +137,14 @@ pub struct ScryptObject { } impl ScryptObject { - fn get_hkdf_key(&self, password: &[u8]) -> std::result::Result, FilenameDecryptError> { + fn get_hkdf_key(&self, password: &[u8]) -> Result, ConfigError> { let mut key = [0u8; 32]; let params = scrypt::Params::new((self.n as f64).log2() as u8, self.r, self.p) .map_err(|e| ScryptError::from(e))?; - scrypt::scrypt( - password, - &base64::decode(&self.salt).unwrap(), - ¶ms, - &mut key, - ) - .map_err(|e| ScryptError::from(e))?; + scrypt::scrypt(password, &base64::decode(&self.salt)?, ¶ms, &mut key) + .map_err(|e| ScryptError::from(e))?; let hdkf = Hkdf::::new(None, &key); hdkf.expand(b"AES-GCM file content encryption", &mut key)?; diff --git a/rustcryptfs-lib/src/content/error.rs b/rustcryptfs-lib/src/content/error.rs new file mode 100644 index 0000000..74bdb54 --- /dev/null +++ b/rustcryptfs-lib/src/content/error.rs @@ -0,0 +1,19 @@ +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum ContentCipherError { + #[error("Block is too short")] + BlockTooShort(), + #[error("all-zero nonce")] + AllZeroNonce(), + #[error("Failed to decrypt content")] + ContentDecryptError(), + #[error(transparent)] + HdkfError(#[from] hkdf::InvalidLength), +} + +impl From for ContentCipherError { + fn from(_: aes_gcm::Error) -> Self { + Self::ContentDecryptError() + } +} diff --git a/rustcryptfs-lib/src/content.rs b/rustcryptfs-lib/src/content/mod.rs similarity index 89% rename from rustcryptfs-lib/src/content.rs rename to rustcryptfs-lib/src/content/mod.rs index 3bc902b..b162095 100644 --- a/rustcryptfs-lib/src/content.rs +++ b/rustcryptfs-lib/src/content/mod.rs @@ -4,7 +4,9 @@ use aes_gcm::{aead::generic_array::GenericArray, aes::Aes256, AeadInPlace, AesGc use cipher::consts::{U16, U32}; use hkdf::Hkdf; -use crate::error::{DecryptError, Result}; +mod error; + +pub use error::*; type Aes256Gcm = AesGcm; @@ -16,16 +18,15 @@ pub struct ContentEnc { impl ContentEnc { /// Init a new ContentEnc from the master key and the iv len. - pub fn new(master_key: &[u8], iv_len: u8) -> Self { + pub fn new(master_key: &[u8], iv_len: u8) -> Result { let mut key = [0u8; 32]; let hdkf = Hkdf::::new(None, &master_key); - hdkf.expand(b"AES-GCM file content encryption", &mut key) - .unwrap(); + hdkf.expand(b"AES-GCM file content encryption", &mut key)?; - Self { + Ok(Self { key: GenericArray::from(key), iv_len: iv_len as usize, - } + }) } /// Decrypt a encrypted block of len (iv_len + decrypted_block_size + iv_len), with the block number and the file id. @@ -34,7 +35,7 @@ impl ContentEnc { block: &[u8], block_number: u64, file_id: Option<&[u8]>, - ) -> Result> { + ) -> Result, ContentCipherError> { // TODO NOT BOX if block.len() == 0 { return Ok(block.into()); @@ -45,7 +46,7 @@ impl ContentEnc { } if block.len() < self.iv_len { - return Err(DecryptError::BlockTooShort().into()); + return Err(ContentCipherError::BlockTooShort().into()); } let nonce = &block[..self.iv_len]; @@ -53,7 +54,7 @@ impl ContentEnc { let ciphertext = &block[self.iv_len..block.len() - self.iv_len]; if nonce.iter().all(|f| *f == 0) { - return Err(DecryptError::AllZeroNonce().into()); + return Err(ContentCipherError::AllZeroNonce().into()); } let mut buf = Vec::from(ciphertext); diff --git a/rustcryptfs-lib/src/error.rs b/rustcryptfs-lib/src/error.rs index 582dcec..ff43e57 100644 --- a/rustcryptfs-lib/src/error.rs +++ b/rustcryptfs-lib/src/error.rs @@ -1,49 +1,19 @@ use thiserror::Error; +use crate::{config::ConfigError, content::ContentCipherError, filename::FilenameCipherError}; + pub type Result = std::result::Result; #[derive(Debug, Error)] pub enum Error { - #[error("Failed to decrypt content")] - ContentDecryptError(), - #[error("Failed to decrypt filename")] - FilenameDecryptError(#[from] FilenameDecryptError), - #[error("Failed to decode base64")] - Base64Error(#[from] base64::DecodeError), #[error(transparent)] - DecodeError(#[from] DecryptError), -} - -impl From for Error { - fn from(_: aes_gcm::Error) -> Self { - Self::ContentDecryptError() - } -} - -#[derive(Debug, Error)] -pub enum DecryptError { - #[error("Block is too short")] - BlockTooShort(), - #[error("all-zero nonce")] - AllZeroNonce(), -} - -#[derive(Debug, Error)] -pub enum FilenameDecryptError { + FilenameCipherError(#[from] FilenameCipherError), #[error(transparent)] - ScryptError(#[from] ScryptError), - #[error("Failed to decode base64")] - Base64Error(#[from] base64::DecodeError), + ContentCipherError(#[from] ContentCipherError), #[error(transparent)] - HdkfError(#[from] hkdf::InvalidLength), - #[error("Failed to decrypt filename")] - DecryptError(), -} - -#[derive(Debug, Error)] -pub enum ScryptError { - #[error(transparent)] - InvalidParams(#[from] scrypt::errors::InvalidParams), - #[error(transparent)] - InvalidOutputLen(#[from] scrypt::errors::InvalidOutputLen), + ConfigError(#[from] ConfigError), + #[error(transparent)] + JsonError(#[from] serde_json::Error), + #[error(transparent)] + IoError(#[from] std::io::Error), } diff --git a/rustcryptfs-lib/src/filename/dir_filename_cipher.rs b/rustcryptfs-lib/src/filename/dir_filename_cipher.rs index deb102a..f7772b0 100644 --- a/rustcryptfs-lib/src/filename/dir_filename_cipher.rs +++ b/rustcryptfs-lib/src/filename/dir_filename_cipher.rs @@ -1,7 +1,6 @@ -use crate::error::FilenameDecryptError; -use cipher::{block_padding::Pkcs7, inout::InOutBufReserved, Iv, Key, KeyIvInit}; +use cipher::{block_padding::Pkcs7, Iv, Key, KeyIvInit}; -use super::{EmeCipher, EncodedFilename, IntoDecodable}; +use super::{EmeCipher, EncodedFilename, FilenameCipherError, IntoDecodable}; pub struct DirFilenameCipher<'a, 'b> { filename_key: &'a Key, @@ -13,7 +12,7 @@ impl<'a, 'b> DirFilenameCipher<'a, 'b> { Self { filename_key, iv } } - pub fn decode_filename(&self, name: S) -> Result + pub fn decode_filename(&self, name: S) -> Result where S: IntoDecodable, { @@ -22,7 +21,7 @@ impl<'a, 'b> DirFilenameCipher<'a, 'b> { let mut filename = base64::decode_config(name.to_decodable(), base64::URL_SAFE_NO_PAD)?; let filename_decoded = cipher .decrypt_padded_mut::(&mut filename) - .map_err(|_| FilenameDecryptError::DecryptError())?; + .map_err(|_| FilenameCipherError::DecryptError())?; Ok(String::from_utf8_lossy(filename_decoded).to_string()) } @@ -30,17 +29,13 @@ impl<'a, 'b> DirFilenameCipher<'a, 'b> { pub fn encrypt_filename( &self, plain_text_name: &str, - ) -> Result { + ) -> Result { let mut cipher = EmeCipher::new(self.filename_key, self.iv); let mut res = [0u8; 2048]; let filename_encrypted = cipher - .encrypt_padded_inout_mut::( - InOutBufReserved::from_slices(plain_text_name.as_bytes(), &mut res).unwrap(), - ) - .map_err(|_| FilenameDecryptError::DecryptError())?; // TODO RENAME ERROR - - // TODO LONG FILENAME + .encrypt_padded_b2b_mut::(plain_text_name.as_bytes(), &mut res) + .map_err(|_| FilenameCipherError::EncryptError())?; let filename = base64::encode_config(filename_encrypted, base64::URL_SAFE_NO_PAD); diff --git a/rustcryptfs-lib/src/filename/error.rs b/rustcryptfs-lib/src/filename/error.rs new file mode 100644 index 0000000..00052e2 --- /dev/null +++ b/rustcryptfs-lib/src/filename/error.rs @@ -0,0 +1,13 @@ +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum FilenameCipherError { + #[error("Failed to decode base64")] + Base64Error(#[from] base64::DecodeError), + #[error(transparent)] + HdkfError(#[from] hkdf::InvalidLength), + #[error("Failed to decrypt filename")] + DecryptError(), + #[error("Failed to encrypt filename")] + EncryptError() +} diff --git a/rustcryptfs-lib/src/filename/mod.rs b/rustcryptfs-lib/src/filename/mod.rs index d836f84..714ff81 100644 --- a/rustcryptfs-lib/src/filename/mod.rs +++ b/rustcryptfs-lib/src/filename/mod.rs @@ -3,22 +3,22 @@ use cipher::{Iv, Key}; use eme_mode::DynamicEme; use hkdf::Hkdf; -use crate::error::FilenameDecryptError; - pub(crate) type EmeCipher = DynamicEme; mod dir_filename_cipher; mod filename_encoded; +mod error; pub use dir_filename_cipher::*; pub use filename_encoded::*; +pub use error::*; pub struct FilenameCipher { filename_key: Key, } impl FilenameCipher { - pub fn new(master_key: &[u8]) -> Result { + pub fn new(master_key: &[u8]) -> Result { let mut key = [0u8; 32]; let hdkf = Hkdf::::new(None, &master_key); hdkf.expand(b"EME filename encryption", &mut key)?; diff --git a/rustcryptfs-lib/src/lib.rs b/rustcryptfs-lib/src/lib.rs index e46bf4e..563bff5 100644 --- a/rustcryptfs-lib/src/lib.rs +++ b/rustcryptfs-lib/src/lib.rs @@ -27,7 +27,7 @@ impl GocryptFs { let base_path = encrypted_dir_path.as_ref(); let mut config_file = - File::open(base_path.join("gocryptfs.conf")).expect("failed to get config"); + File::open(base_path.join("gocryptfs.conf"))?; Self::load_from_reader(&mut config_file, password.as_bytes()) } @@ -39,13 +39,12 @@ impl GocryptFs { where R: Read, { - let config = serde_json::from_reader::<_, config::CryptConf>(reader_config) - .expect("failed to parse config"); + let config = serde_json::from_reader::<_, config::CryptConf>(reader_config)?; let master_key = config.get_master_key(password)?; let filename_decoder = FilenameCipher::new(&master_key)?; - let content_decoder = ContentEnc::new(&master_key, 16); // TODO IV LEN + let content_decoder = ContentEnc::new(&master_key, 16)?; // TODO IV LEN Ok(Self { filename_decoder, diff --git a/rustcryptfs-linux/src/error.rs b/rustcryptfs-linux/src/error.rs index c0215e7..f180b80 100644 --- a/rustcryptfs-linux/src/error.rs +++ b/rustcryptfs-linux/src/error.rs @@ -1,3 +1,4 @@ +use rustcryptfs_lib::filename::FilenameCipherError; use thiserror::Error; pub type Result = std::result::Result; @@ -11,5 +12,5 @@ pub enum Error { RustCryptFsError(#[from] rustcryptfs_lib::error::Error), #[error(transparent)] - RustCryptFsFilenameError(#[from] rustcryptfs_lib::error::FilenameDecryptError), + RustCryptFsFilenameError(#[from] FilenameCipherError), } From 4b93f8071f6f8b794b5bcba66fcfb62f18fb4036 Mon Sep 17 00:00:00 2001 From: oupson Date: Sat, 8 Oct 2022 16:16:17 +0200 Subject: [PATCH 28/36] Remove useless new function for EncodedFilename --- .../src/filename/filename_encoded.rs | 34 ------------------- 1 file changed, 34 deletions(-) diff --git a/rustcryptfs-lib/src/filename/filename_encoded.rs b/rustcryptfs-lib/src/filename/filename_encoded.rs index fdfd949..dcac5e1 100644 --- a/rustcryptfs-lib/src/filename/filename_encoded.rs +++ b/rustcryptfs-lib/src/filename/filename_encoded.rs @@ -1,5 +1,3 @@ -use std::path::Path; - use sha2::{Digest, Sha256}; /// EncodedFilename @@ -9,38 +7,6 @@ pub enum EncodedFilename { LongFilename(LongFilename), } -impl EncodedFilename { - fn new

(file: P) -> crate::error::Result - where - P: AsRef, - { - let path = file.as_ref(); - - let filename = path - .file_name() - .unwrap() - .to_str() - .expect("Failed to get filename"); - - if filename.starts_with("gocryptfs.longname.") { - if !filename.ends_with(".name") { - let long = std::fs::read_to_string( - path.parent().unwrap().join(format!("{}.name", filename)), - ) - .unwrap(); - Ok(EncodedFilename::LongFilename(LongFilename { - filename: filename.to_string(), - filename_content: long, - })) - } else { - panic!() - } - } else { - Ok(EncodedFilename::ShortFilename(filename.to_string())) - } - } -} - #[derive(Debug, PartialEq)] pub struct LongFilename { pub filename: String, From 61d07910e679178e76fc952fadcffb750c73f3b2 Mon Sep 17 00:00:00 2001 From: oupson Date: Sat, 8 Oct 2022 16:23:52 +0200 Subject: [PATCH 29/36] Cargo clippy in rustcryptfs-lib --- rustcryptfs-lib/src/config/mod.rs | 6 +++--- rustcryptfs-lib/src/content/mod.rs | 10 +++++----- rustcryptfs-lib/src/filename/filename_encoded.rs | 12 ++++++------ rustcryptfs-lib/src/filename/mod.rs | 2 +- rustcryptfs-lib/src/lib.rs | 2 +- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/rustcryptfs-lib/src/config/mod.rs b/rustcryptfs-lib/src/config/mod.rs index e8ea895..5be2d69 100644 --- a/rustcryptfs-lib/src/config/mod.rs +++ b/rustcryptfs-lib/src/config/mod.rs @@ -86,7 +86,7 @@ impl CryptConf { let aes = AesGcm::::new(Key::from_slice(&key)); aes.decrypt_in_place_detached( - GenericArray::from_slice(&nonce), + GenericArray::from_slice(nonce), &[0u8, 0, 0, 0, 0, 0, 0, 0], &mut buf, GenericArray::from_slice(tag), @@ -141,10 +141,10 @@ impl ScryptObject { let mut key = [0u8; 32]; let params = scrypt::Params::new((self.n as f64).log2() as u8, self.r, self.p) - .map_err(|e| ScryptError::from(e))?; + .map_err(ScryptError::from)?; scrypt::scrypt(password, &base64::decode(&self.salt)?, ¶ms, &mut key) - .map_err(|e| ScryptError::from(e))?; + .map_err(ScryptError::from)?; let hdkf = Hkdf::::new(None, &key); hdkf.expand(b"AES-GCM file content encryption", &mut key)?; diff --git a/rustcryptfs-lib/src/content/mod.rs b/rustcryptfs-lib/src/content/mod.rs index b162095..f5d1811 100644 --- a/rustcryptfs-lib/src/content/mod.rs +++ b/rustcryptfs-lib/src/content/mod.rs @@ -20,7 +20,7 @@ impl ContentEnc { /// Init a new ContentEnc from the master key and the iv len. pub fn new(master_key: &[u8], iv_len: u8) -> Result { let mut key = [0u8; 32]; - let hdkf = Hkdf::::new(None, &master_key); + let hdkf = Hkdf::::new(None, master_key); hdkf.expand(b"AES-GCM file content encryption", &mut key)?; Ok(Self { @@ -37,7 +37,7 @@ impl ContentEnc { file_id: Option<&[u8]>, ) -> Result, ContentCipherError> { // TODO NOT BOX - if block.len() == 0 { + if block.is_empty() { return Ok(block.into()); } @@ -46,7 +46,7 @@ impl ContentEnc { } if block.len() < self.iv_len { - return Err(ContentCipherError::BlockTooShort().into()); + return Err(ContentCipherError::BlockTooShort()); } let nonce = &block[..self.iv_len]; @@ -54,7 +54,7 @@ impl ContentEnc { let ciphertext = &block[self.iv_len..block.len() - self.iv_len]; if nonce.iter().all(|f| *f == 0) { - return Err(ContentCipherError::AllZeroNonce().into()); + return Err(ContentCipherError::AllZeroNonce()); } let mut buf = Vec::from(ciphertext); @@ -73,7 +73,7 @@ impl ContentEnc { GenericArray::from_slice(tag), )?; - return Ok(buf.to_vec()); + Ok(buf.to_vec()) } /// Return the decrypted size of a file, based on the encrypted size. diff --git a/rustcryptfs-lib/src/filename/filename_encoded.rs b/rustcryptfs-lib/src/filename/filename_encoded.rs index dcac5e1..bbcf2de 100644 --- a/rustcryptfs-lib/src/filename/filename_encoded.rs +++ b/rustcryptfs-lib/src/filename/filename_encoded.rs @@ -1,13 +1,13 @@ use sha2::{Digest, Sha256}; /// EncodedFilename -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] pub enum EncodedFilename { ShortFilename(String), LongFilename(LongFilename), } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] pub struct LongFilename { pub filename: String, pub filename_content: String, @@ -33,11 +33,11 @@ impl From for EncodedFilename { } pub trait IntoDecodable { - fn to_decodable<'s>(&'s self) -> &'s str; + fn to_decodable(&self) -> &str; } impl IntoDecodable for EncodedFilename { - fn to_decodable<'s>(&'s self) -> &'s str { + fn to_decodable(&self) -> &str { match self { Self::ShortFilename(s) => s.as_str(), Self::LongFilename(l) => l.filename_content.as_str(), @@ -46,13 +46,13 @@ impl IntoDecodable for EncodedFilename { } impl IntoDecodable for String { - fn to_decodable<'s>(&'s self) -> &'s str { + fn to_decodable(&self) -> &str { self } } impl<'a> IntoDecodable for &'a str { - fn to_decodable<'s>(&'s self) -> &'s str { + fn to_decodable(&self) -> &str { self } } diff --git a/rustcryptfs-lib/src/filename/mod.rs b/rustcryptfs-lib/src/filename/mod.rs index 714ff81..8ec6d42 100644 --- a/rustcryptfs-lib/src/filename/mod.rs +++ b/rustcryptfs-lib/src/filename/mod.rs @@ -20,7 +20,7 @@ pub struct FilenameCipher { impl FilenameCipher { pub fn new(master_key: &[u8]) -> Result { let mut key = [0u8; 32]; - let hdkf = Hkdf::::new(None, &master_key); + let hdkf = Hkdf::::new(None, master_key); hdkf.expand(b"EME filename encryption", &mut key)?; Ok(Self { diff --git a/rustcryptfs-lib/src/lib.rs b/rustcryptfs-lib/src/lib.rs index 563bff5..5b13dfd 100644 --- a/rustcryptfs-lib/src/lib.rs +++ b/rustcryptfs-lib/src/lib.rs @@ -53,7 +53,7 @@ impl GocryptFs { } /// Get the [`filename decoder`](struct@FilenameDecoder) attached to this GocryptFs. - pub fn filename_decoder<'s>(&'s self) -> &'s FilenameCipher { + pub fn filename_decoder(&self) -> &FilenameCipher { &self.filename_decoder } From 2032d861dd48ec87edb263f0cd49ffd268b483fb Mon Sep 17 00:00:00 2001 From: oupson Date: Sat, 8 Oct 2022 20:58:48 +0200 Subject: [PATCH 30/36] Refracto error handling on rustcryptfs-linux --- rustcryptfs-linux/src/encrypted_filesystem.rs | 372 ++++++++++-------- rustcryptfs-linux/src/error.rs | 17 + rustcryptfs/src/main.rs | 4 +- 3 files changed, 235 insertions(+), 158 deletions(-) diff --git a/rustcryptfs-linux/src/encrypted_filesystem.rs b/rustcryptfs-linux/src/encrypted_filesystem.rs index 3331375..58616c5 100644 --- a/rustcryptfs-linux/src/encrypted_filesystem.rs +++ b/rustcryptfs-linux/src/encrypted_filesystem.rs @@ -2,7 +2,7 @@ use std::{ collections::BTreeMap, ffi::OsStr, fs::{File, FileType as StdFileType}, - io::{Read, Seek, SeekFrom}, + io::{Error as IoError, Read, Result as IoResult, Seek, SeekFrom}, ops::Add, os::unix::prelude::{FileTypeExt, MetadataExt, OsStrExt, PermissionsExt}, path::{Path, PathBuf}, @@ -13,10 +13,23 @@ use fuser::{FileAttr, FileType, Filesystem, FUSE_ROOT_ID}; use rustcryptfs_lib::{content::ContentEnc, GocryptFs}; use crate::{ - error::Result, + error::{ErrorExt, Result}, inode_cache::{InodeCache, InodeCacheExt}, }; +trait OptionExt { + fn enoent(self) -> IoResult; +} + +impl OptionExt for Option { + fn enoent(self) -> IoResult { + match self { + Some(r) => Ok(r), + None => Err(IoError::from_raw_os_error(libc::ENOENT)), + } + } +} + const BLOCK_SIZE: u64 = 4096; pub struct EncryptedFs { @@ -42,11 +55,11 @@ impl EncryptedFs { Ok(Self { fs, inode_cache }) } - pub fn mount

(self, mountpoint: P) + pub fn mount

(self, mountpoint: P) -> std::io::Result<()> where P: AsRef, { - fuser::mount2(self, mountpoint, &[]).unwrap(); + fuser::mount2(self, mountpoint, &[]) } fn get_file_type(file_type: StdFileType) -> FileType { @@ -73,11 +86,11 @@ impl EncryptedFs { self.inode_cache.get_path(ino) } - fn get_attr

(path: P, ino: u64) -> FileAttr + fn get_attr

(path: P, ino: u64) -> std::io::Result where P: AsRef, { - let meta = std::fs::metadata(&path).unwrap(); + let meta = std::fs::metadata(&path)?; let file_type = Self::get_file_type(meta.file_type()); @@ -87,12 +100,12 @@ impl EncryptedFs { meta.size() }; - FileAttr { + Ok(FileAttr { ino, size: file_size, blocks: (file_size + BLOCK_SIZE - 1) / BLOCK_SIZE, - atime: meta.accessed().unwrap(), - mtime: meta.modified().unwrap(), + atime: meta.accessed()?, + mtime: meta.modified()?, ctime: UNIX_EPOCH.add(Duration::new(meta.ctime() as u64, 0)), crtime: UNIX_EPOCH.add(Duration::new(meta.ctime() as u64, 0)), kind: file_type, @@ -103,13 +116,170 @@ impl EncryptedFs { rdev: 0, blksize: BLOCK_SIZE as u32, flags: 0, + }) + } + + fn lookup_impl( + &mut self, + parent: u64, + name: &std::ffi::OsStr, + ) -> rustcryptfs_lib::error::Result<(Duration, FileAttr, u64)> { + let parent = self.get_path(parent).enoent()?; + let iv = std::fs::read(parent.join("gocryptfs.diriv"))?; + let dir_decoder = self.fs.filename_decoder().get_cipher_for_dir(&iv); + + let encrypted_name = dir_decoder.encrypt_filename(&name.to_string_lossy())?; + + let encrypted_name = match encrypted_name { + rustcryptfs_lib::filename::EncodedFilename::ShortFilename(s) => s, + rustcryptfs_lib::filename::EncodedFilename::LongFilename(l) => l.filename, + }; + + let file_path = parent.join(encrypted_name); + + if file_path.exists() { + let (ino, file_path) = self.inode_cache.get_or_insert_inode(file_path); + + Ok((Duration::new(0, 0), Self::get_attr(file_path, ino)?, 0)) + } else { + Err(IoError::from_raw_os_error(libc::ENOENT).into()) } } + + fn read_dir_impl( + &mut self, + ino: u64, + offset: i64, + reply: &mut fuser::ReplyDirectory, + ) -> rustcryptfs_lib::error::Result<()> { + let folder_path = &self.inode_cache.get_path(ino).enoent()?.clone(); + let iv = std::fs::read(folder_path.join("gocryptfs.diriv"))?; + + let dir_decoder = self.fs.filename_decoder().get_cipher_for_dir(&iv); + + if offset == 0 { + let ino_parent = if ino == FUSE_ROOT_ID { + FUSE_ROOT_ID + } else { + let parent = folder_path.parent().enoent()?; + self.inode_cache + .iter() + .find_map(|(ino, p)| if p == parent { Some(*ino) } else { None }) + .enoent()? + }; + + if !reply.add(ino, 1, FileType::Directory, ".") { + if reply.add(ino_parent, 2, FileType::Directory, "..") { + return Ok(()); + } + } else { + return Ok(()); + } + } + + for (index, (meta, encrypted_name, name)) in std::fs::read_dir(folder_path)? + .flat_map(|e| e.ok()) + .flat_map(|dir| match extract_name(&dir, folder_path, &dir_decoder) { + Ok(v) => v, + Err(e) => { + log::error!( + "Failed to extract name of entry {:?} : {}", + dir.file_name(), + e + ); + None + } + }) + .skip(offset as usize) + .enumerate() + { + let (inode, _) = self + .inode_cache + .get_or_insert_inode(folder_path.join(&encrypted_name)); + + let file_type = Self::get_file_type(meta.file_type()); + + let buffer_full: bool = reply.add( + inode, + offset + index as i64 + 1 + 2, + file_type, + OsStr::from_bytes(name.as_bytes()), + ); + + if buffer_full { + break; + } + } + Ok(()) + } + + fn read_impl( + &mut self, + ino: u64, + offset: i64, + size: usize, + ) -> rustcryptfs_lib::error::Result> { + let file_path = self.get_path(ino).enoent()?; + let mut file = File::open(file_path)?; + let decoder = self.fs.content_decoder(); + + let mut buf = [0u8; 18]; + let n = file.read(&mut buf)?; + let id = if n < 18 { None } else { Some(&buf[2..]) }; + + let mut block_index = offset as u64 / 4096; + + let mut buffer = Vec::with_capacity(size); + + let mut rem = size; + + let mut buf = [0u8; 4096 + 32]; + + file.seek(SeekFrom::Start(18 + block_index * (4096 + 32)))?; + + { + let n = file.read(&mut buf)?; + + let res = decoder.decrypt_block(&buf[..n], block_index, id)?; + + let seek = (offset as u64 - block_index * 4096) as usize; + buffer.extend_from_slice(&res[seek..]); + + block_index += 1; + + rem -= res.len() - seek; + } + + while rem > 0 { + let n = file.read(&mut buf)?; + + if n == 0 { + break; + } + + let res = decoder.decrypt_block(&buf[..n], block_index, id)?; + + let size = res.len().min(rem); + + buffer.extend_from_slice(&res[..size]); + + block_index += 1; + + rem -= size; + } + Ok(buffer) + } } impl Filesystem for EncryptedFs { - fn access(&mut self, _req: &fuser::Request<'_>, ino: u64, mask: i32, reply: fuser::ReplyEmpty) { - if let Some(path) = self.get_path(ino) { + fn access( + &mut self, + _req: &fuser::Request<'_>, + ino: u64, + _mask: i32, + reply: fuser::ReplyEmpty, + ) { + if let Some(_path) = self.get_path(ino) { reply.ok() } else { reply.error(libc::ENOENT) @@ -118,7 +288,10 @@ impl Filesystem for EncryptedFs { fn getattr(&mut self, _req: &fuser::Request<'_>, ino: u64, reply: fuser::ReplyAttr) { if let Some(path) = self.get_path(ino) { - reply.attr(&Duration::new(0, 0), &Self::get_attr(path, ino)) + match Self::get_attr(path, ino) { + Ok(attr) => reply.attr(&Duration::new(0, 0), &attr), + Err(e) => reply.error(e.raw_os_error().unwrap()), + } } else { reply.error(libc::ENOENT) } @@ -131,30 +304,12 @@ impl Filesystem for EncryptedFs { name: &std::ffi::OsStr, reply: fuser::ReplyEntry, ) { - if let Some(parent) = &self.get_path(parent) { - let iv = std::fs::read(parent.join("gocryptfs.diriv")).unwrap(); - let dir_decoder = self.fs.filename_decoder().get_cipher_for_dir(&iv); - - let encrypted_name = dir_decoder - .encrypt_filename(&name.to_string_lossy()) - .unwrap(); - - let encrypted_name = match encrypted_name { - rustcryptfs_lib::filename::EncodedFilename::ShortFilename(s) => s, - rustcryptfs_lib::filename::EncodedFilename::LongFilename(l) => l.filename, - }; - - let file_path = parent.join(encrypted_name); - - if file_path.exists() { - let (ino, file_path) = self.inode_cache.get_or_insert_inode(file_path); - - reply.entry(&Duration::new(0, 0), &Self::get_attr(file_path, ino), 0) - } else { - reply.error(libc::ENOENT) + match self.lookup_impl(parent, name) { + Ok((ttl, attr, generation)) => reply.entry(&ttl, &attr, generation), + Err(e) => { + log::error!("lookup : {}", e); + reply.error(e.to_raw_code()) } - } else { - reply.error(libc::ENOENT) } } @@ -166,61 +321,12 @@ impl Filesystem for EncryptedFs { offset: i64, mut reply: fuser::ReplyDirectory, ) { - if let Some(folder_path) = &self.inode_cache.get_path(ino).cloned() { - let iv = std::fs::read(folder_path.join("gocryptfs.diriv")).unwrap(); - - let dir_decoder = self.fs.filename_decoder().get_cipher_for_dir(&iv); - - if offset == 0 { - let ino_parent = if ino == FUSE_ROOT_ID { - FUSE_ROOT_ID - } else { - let parent = folder_path.parent().expect("Failed to get parent"); - self.inode_cache - .iter() - .find_map(|(ino, p)| if p == parent { Some(*ino) } else { None }) - .expect("Parent inode not found") - }; - - if !reply.add(ino, 1, FileType::Directory, ".") { - if reply.add(ino_parent, 2, FileType::Directory, "..") { - reply.ok(); - return; - } - } else { - reply.ok(); - return; - } + match self.read_dir_impl(ino, offset, &mut reply) { + Ok(()) => reply.ok(), + Err(e) => { + log::error!("readdir : {}", e); + reply.error(e.to_raw_code()) } - - for (index, (meta, encrypted_name, name)) in std::fs::read_dir(folder_path) - .unwrap() - .flat_map(|e| e.ok()) - .flat_map(|dir| extract_name(dir, folder_path, &dir_decoder)) - .skip(offset as usize) - .enumerate() - { - let (inode, _) = self - .inode_cache - .get_or_insert_inode(folder_path.join(&encrypted_name)); - - let file_type = Self::get_file_type(meta.file_type()); - - let buffer_full: bool = reply.add( - inode, - offset + index as i64 + 1 + 2, - file_type, - OsStr::from_bytes(name.as_bytes()), - ); - - if buffer_full { - break; - } - } - - reply.ok() - } else { - reply.error(libc::ENOENT) } } @@ -235,90 +341,42 @@ impl Filesystem for EncryptedFs { _lock_owner: Option, reply: fuser::ReplyData, ) { - if let Some(file_path) = &self.get_path(ino) { - let mut file = File::open(file_path).unwrap(); - let decoder = self.fs.content_decoder(); - - let mut buf = [0u8; 18]; - let n = file.read(&mut buf).unwrap(); - let id = if n < 18 { None } else { Some(&buf[2..]) }; - - let mut block_index = offset as u64 / 4096; - - let mut buffer = Vec::with_capacity(size as usize); - - let mut rem = size as usize; - - let mut buf = [0u8; 4096 + 32]; - - file.seek(SeekFrom::Start(18 + block_index * (4096 + 32))) - .unwrap(); - - { - let n = file.read(&mut buf).unwrap(); - - let res = decoder.decrypt_block(&buf[..n], block_index, id).unwrap(); - - let seek = (offset as u64 - block_index * 4096) as usize; - buffer.extend_from_slice(&res[seek..]); - - block_index += 1; - - rem -= res.len() - seek; + match self.read_impl(ino, offset, size as usize) { + Ok(data) => reply.data(&data), + Err(e) => { + log::error!("read : {}", e); + reply.error(e.to_raw_code()) } - - while rem > 0 { - let n = file.read(&mut buf).unwrap(); - - if n == 0 { - break; - } - - let res = decoder.decrypt_block(&buf[..n], block_index, id).unwrap(); - - let size = res.len().min(rem); - - buffer.extend_from_slice(&res[..size]); - - block_index += 1; - - rem -= size; - } - - reply.data(&buffer); - } else { - reply.error(libc::ENOENT) } } } fn extract_name( - dir: std::fs::DirEntry, - folder_path: &PathBuf, + dir: &std::fs::DirEntry, + folder_path: &Path, dir_decoder: &rustcryptfs_lib::filename::DirFilenameCipher, -) -> Option<(std::fs::Metadata, String, String)> { +) -> rustcryptfs_lib::error::Result> { let filename = dir.file_name(); - let filename = filename.to_str().unwrap(); + let filename = filename.to_string_lossy(); if filename != "gocryptfs.conf" && filename != "gocryptfs.diriv" { if filename.starts_with("gocryptfs.longname.") { if !filename.ends_with(".name") { let filename = - std::fs::read_to_string(folder_path.join(format!("{}.name", filename))) - .unwrap(); - dir_decoder - .decode_filename(filename.as_str()) - .map(|n| (dir.metadata().unwrap(), filename, n)) - .ok() + std::fs::read_to_string(folder_path.join(format!("{}.name", filename)))?; + let decrypted_filename = dir_decoder.decode_filename(filename.as_str())?; + Ok(Some((dir.metadata()?, filename, decrypted_filename))) } else { - None + Ok(None) } } else { - dir_decoder - .decode_filename(filename) - .map(|n| (dir.metadata().unwrap(), filename.to_string(), n)) - .ok() + let decrypted_filename = dir_decoder.decode_filename(&*filename)?; + Ok(Some(( + dir.metadata()?, + filename.to_string(), + decrypted_filename, + ))) } } else { - None + Ok(None) } } diff --git a/rustcryptfs-linux/src/error.rs b/rustcryptfs-linux/src/error.rs index f180b80..13b06cf 100644 --- a/rustcryptfs-linux/src/error.rs +++ b/rustcryptfs-linux/src/error.rs @@ -14,3 +14,20 @@ pub enum Error { #[error(transparent)] RustCryptFsFilenameError(#[from] FilenameCipherError), } + + +pub(crate) trait ErrorExt { + fn to_raw_code(&self) -> i32; +} + +impl ErrorExt for rustcryptfs_lib::error::Error { + fn to_raw_code(&self) -> i32 { + match self { + rustcryptfs_lib::error::Error::FilenameCipherError(_) => libc::EIO, + rustcryptfs_lib::error::Error::ContentCipherError(_) => libc::EIO, + rustcryptfs_lib::error::Error::ConfigError(_) => todo!(), + rustcryptfs_lib::error::Error::JsonError(_) => todo!(), + rustcryptfs_lib::error::Error::IoError(e) => e.raw_os_error().unwrap(), + } + } +} \ No newline at end of file diff --git a/rustcryptfs/src/main.rs b/rustcryptfs/src/main.rs index 57fe597..979c5d3 100644 --- a/rustcryptfs/src/main.rs +++ b/rustcryptfs/src/main.rs @@ -119,6 +119,7 @@ fn decrypt_file(c: &DecryptCommand) -> anyhow::Result<()> { #[cfg(target_os = "linux")] fn mount(mount: &MountCommand) -> anyhow::Result<()> { + use anyhow::Context; use rustcryptfs_linux::EncryptedFs; let password = if let Some(password) = &mount.password { @@ -129,7 +130,8 @@ fn mount(mount: &MountCommand) -> anyhow::Result<()> { let fs = EncryptedFs::new(&mount.path, &password)?; - fs.mount(&mount.mountpoint); + fs.mount(&mount.mountpoint) + .context("Failed to run fuse fs")?; Ok(()) } From 0499bd782b883dd3fdab57be8c7668e64ebe189b Mon Sep 17 00:00:00 2001 From: oupson Date: Sat, 8 Oct 2022 21:01:39 +0200 Subject: [PATCH 31/36] Apply clippy lint --- rustcryptfs/src/main.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/rustcryptfs/src/main.rs b/rustcryptfs/src/main.rs index 979c5d3..bbad968 100644 --- a/rustcryptfs/src/main.rs +++ b/rustcryptfs/src/main.rs @@ -35,7 +35,7 @@ fn ls(c: &LsCommand) -> anyhow::Result<()> { let fs = GocryptFs::open( c.gocryptfs_path .as_ref() - .map(|p| Path::new(p)) + .map(Path::new) .unwrap_or(folder_path), &password, )?; @@ -59,15 +59,13 @@ fn ls(c: &LsCommand) -> anyhow::Result<()> { println!("{}", res); } } - } else { - if let Ok(res) = dir_decoder.decode_filename(filename) { - println!("{}", res); - } - }; + } else if let Ok(res) = dir_decoder.decode_filename(filename) { + println!("{}", res); + } } } - return Ok(()); + Ok(()) } fn decrypt_file(c: &DecryptCommand) -> anyhow::Result<()> { @@ -82,7 +80,7 @@ fn decrypt_file(c: &DecryptCommand) -> anyhow::Result<()> { let fs = GocryptFs::open( c.gocryptfs_path .as_ref() - .map(|p| Path::new(p)) + .map(Path::new) .unwrap_or_else(|| file_path.parent().unwrap()), &password, )?; @@ -106,7 +104,7 @@ fn decrypt_file(c: &DecryptCommand) -> anyhow::Result<()> { stdout.write_all(&res)?; - if res.len() == 0 { + if res.is_empty() { break; } From e75555d845d11880fdb7195866b49bb70c1d2102 Mon Sep 17 00:00:00 2001 From: oupson Date: Sat, 8 Oct 2022 21:42:02 +0200 Subject: [PATCH 32/36] Document rustcryptfs-lib --- rustcryptfs-lib/src/error.rs | 1 + .../src/filename/dir_filename_cipher.rs | 7 +++++++ .../src/filename/filename_encoded.rs | 19 ++++++++++++++++--- rustcryptfs-lib/src/filename/mod.rs | 9 +++++++-- rustcryptfs-lib/src/lib.rs | 2 +- 5 files changed, 32 insertions(+), 6 deletions(-) diff --git a/rustcryptfs-lib/src/error.rs b/rustcryptfs-lib/src/error.rs index ff43e57..fa68606 100644 --- a/rustcryptfs-lib/src/error.rs +++ b/rustcryptfs-lib/src/error.rs @@ -4,6 +4,7 @@ use crate::{config::ConfigError, content::ContentCipherError, filename::Filename pub type Result = std::result::Result; +/// An error that wrap all the errors in this lib. #[derive(Debug, Error)] pub enum Error { #[error(transparent)] diff --git a/rustcryptfs-lib/src/filename/dir_filename_cipher.rs b/rustcryptfs-lib/src/filename/dir_filename_cipher.rs index f7772b0..26db9ab 100644 --- a/rustcryptfs-lib/src/filename/dir_filename_cipher.rs +++ b/rustcryptfs-lib/src/filename/dir_filename_cipher.rs @@ -2,6 +2,9 @@ use cipher::{block_padding::Pkcs7, Iv, Key, KeyIvInit}; use super::{EmeCipher, EncodedFilename, FilenameCipherError, IntoDecodable}; +/// DirFilenameCipher allow you to cipher and decipher filenames in a directory. +/// +/// TODO : document structure of a gocryptfs dir or put a link. pub struct DirFilenameCipher<'a, 'b> { filename_key: &'a Key, iv: &'b Iv, @@ -12,6 +15,9 @@ impl<'a, 'b> DirFilenameCipher<'a, 'b> { Self { filename_key, iv } } + /// Decipher a filename. + /// + /// Name muste be the name of the file if it is a short filename, or the content of the long .name file otherwise. pub fn decode_filename(&self, name: S) -> Result where S: IntoDecodable, @@ -26,6 +32,7 @@ impl<'a, 'b> DirFilenameCipher<'a, 'b> { Ok(String::from_utf8_lossy(filename_decoded).to_string()) } + /// Cipher a filename. pub fn encrypt_filename( &self, plain_text_name: &str, diff --git a/rustcryptfs-lib/src/filename/filename_encoded.rs b/rustcryptfs-lib/src/filename/filename_encoded.rs index bbcf2de..a708122 100644 --- a/rustcryptfs-lib/src/filename/filename_encoded.rs +++ b/rustcryptfs-lib/src/filename/filename_encoded.rs @@ -1,6 +1,9 @@ use sha2::{Digest, Sha256}; -/// EncodedFilename +/// Represent an encrypted filename. +/// +/// An encrypted filename can have two forms : long or short. +/// TODO: Document #[derive(Debug, PartialEq, Eq)] pub enum EncodedFilename { ShortFilename(String), @@ -9,8 +12,18 @@ pub enum EncodedFilename { #[derive(Debug, PartialEq, Eq)] pub struct LongFilename { - pub filename: String, - pub filename_content: String, + filename: String, + filename_content: String, +} + +impl LongFilename { + pub fn filename(&self) -> &str { + self.filename.as_ref() + } + + pub fn filename_content(&self) -> &str { + self.filename_content.as_ref() + } } impl From for EncodedFilename { diff --git a/rustcryptfs-lib/src/filename/mod.rs b/rustcryptfs-lib/src/filename/mod.rs index 8ec6d42..3adcab8 100644 --- a/rustcryptfs-lib/src/filename/mod.rs +++ b/rustcryptfs-lib/src/filename/mod.rs @@ -1,3 +1,5 @@ +//! Utilities for filename encryption. +//! use aes::Aes256; use cipher::{Iv, Key}; use eme_mode::DynamicEme; @@ -6,18 +8,20 @@ use hkdf::Hkdf; pub(crate) type EmeCipher = DynamicEme; mod dir_filename_cipher; -mod filename_encoded; mod error; +mod filename_encoded; pub use dir_filename_cipher::*; -pub use filename_encoded::*; pub use error::*; +pub use filename_encoded::*; +/// FilenameCipher allow you to retrieve a DirFilenameCipher, used to cipher and decipher filenames. pub struct FilenameCipher { filename_key: Key, } impl FilenameCipher { + /// Create a new FilenameCipher, from the master key. pub fn new(master_key: &[u8]) -> Result { let mut key = [0u8; 32]; let hdkf = Hkdf::::new(None, master_key); @@ -28,6 +32,7 @@ impl FilenameCipher { }) } + /// Get the cipher for a directory, allowing you to decipher files in this dir. pub fn get_cipher_for_dir<'a, 'b>(&'a self, iv: &'b [u8]) -> DirFilenameCipher<'a, 'b> { let iv = Iv::::from_slice(iv); DirFilenameCipher::new(&self.filename_key, iv) diff --git a/rustcryptfs-lib/src/lib.rs b/rustcryptfs-lib/src/lib.rs index 5b13dfd..60122eb 100644 --- a/rustcryptfs-lib/src/lib.rs +++ b/rustcryptfs-lib/src/lib.rs @@ -52,7 +52,7 @@ impl GocryptFs { }) } - /// Get the [`filename decoder`](struct@FilenameDecoder) attached to this GocryptFs. + /// Get the [`filename decoder`](struct@FilenameCipher) attached to this GocryptFs. pub fn filename_decoder(&self) -> &FilenameCipher { &self.filename_decoder } From 400dc538e14920308f53ecb1e282b4e580c4722a Mon Sep 17 00:00:00 2001 From: oupson Date: Sat, 8 Oct 2022 21:57:30 +0200 Subject: [PATCH 33/36] Rename rustcryptfs-linux to rustcryptfs-fuse and cargo update --- Cargo.lock | 166 +++++++++--------- Cargo.toml | 2 +- .../Cargo.toml | 2 +- .../src/encrypted_filesystem.rs | 4 +- .../src/error.rs | 0 .../src/inode_cache.rs | 0 .../src/lib.rs | 0 rustcryptfs/Cargo.toml | 2 +- rustcryptfs/src/main.rs | 2 +- 9 files changed, 89 insertions(+), 89 deletions(-) rename {rustcryptfs-linux => rustcryptfs-fuse}/Cargo.toml (86%) rename {rustcryptfs-linux => rustcryptfs-fuse}/src/encrypted_filesystem.rs (99%) rename {rustcryptfs-linux => rustcryptfs-fuse}/src/error.rs (100%) rename {rustcryptfs-linux => rustcryptfs-fuse}/src/inode_cache.rs (100%) rename {rustcryptfs-linux => rustcryptfs-fuse}/src/lib.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index d1e2398..4f3f80e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -50,18 +50,18 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.18" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.57" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" +checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" [[package]] name = "atty" @@ -100,9 +100,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "block-buffer" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" dependencies = [ "generic-array", ] @@ -149,16 +149,16 @@ dependencies = [ [[package]] name = "clap" -version = "3.1.18" +version = "3.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b" +checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" dependencies = [ "atty", "bitflags", "clap_derive", "clap_lex", "indexmap", - "lazy_static", + "once_cell", "strsim", "termcolor", "textwrap", @@ -166,9 +166,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "3.1.18" +version = "3.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25320346e922cffe59c0bbc5410c8d8784509efb321488971081313cb1e1a33c" +checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" dependencies = [ "heck", "proc-macro-error", @@ -179,27 +179,27 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.2.0" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" dependencies = [ "os_str_bytes", ] [[package]] name = "cpufeatures" -version = "0.2.2" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" dependencies = [ "libc", ] [[package]] name = "crypto-common" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "typenum", @@ -216,9 +216,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" dependencies = [ "block-buffer", "crypto-common", @@ -236,9 +236,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +checksum = "c90bf5f19754d10198ccb95b70664fc925bd1fc090a0fd9a6ebc54acc8cd6272" dependencies = [ "atty", "humantime", @@ -265,9 +265,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.5" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ "typenum", "version_check", @@ -275,9 +275,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" dependencies = [ "cfg-if", "libc", @@ -296,9 +296,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "heck" @@ -341,9 +341,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "indexmap" -version = "1.8.1" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", "hashbrown", @@ -361,15 +361,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" [[package]] name = "libc" @@ -392,6 +386,12 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "once_cell" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" + [[package]] name = "opaque-debug" version = "0.3.0" @@ -400,9 +400,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "os_str_bytes" -version = "6.0.1" +version = "6.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "029d8d0b2f198229de29dca79676f2738ff952edf3fde542eb8bf94d8c21b435" +checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" [[package]] name = "page_size" @@ -478,36 +478,36 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.18" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] [[package]] name = "rand_core" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] [[package]] name = "regex" -version = "1.5.6" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ "aho-corasick", "memchr", @@ -516,9 +516,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.26" +version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] name = "rpassword" @@ -539,12 +539,23 @@ dependencies = [ "env_logger", "log", "rpassword", + "rustcryptfs-fuse", "rustcryptfs-lib", - "rustcryptfs-linux", "serde", "serde_json", ] +[[package]] +name = "rustcryptfs-fuse" +version = "0.1.0" +dependencies = [ + "fuser", + "libc", + "log", + "rustcryptfs-lib", + "thiserror", +] + [[package]] name = "rustcryptfs-lib" version = "0.1.0" @@ -562,22 +573,11 @@ dependencies = [ "thiserror", ] -[[package]] -name = "rustcryptfs-linux" -version = "0.1.0" -dependencies = [ - "fuser", - "libc", - "log", - "rustcryptfs-lib", - "thiserror", -] - [[package]] name = "ryu" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" [[package]] name = "salsa20" @@ -603,18 +603,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.137" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.137" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" dependencies = [ "proc-macro2", "quote", @@ -623,9 +623,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.81" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" dependencies = [ "itoa", "ryu", @@ -634,9 +634,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.2" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if", "cpufeatures", @@ -663,9 +663,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.95" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" dependencies = [ "proc-macro2", "quote", @@ -695,24 +695,24 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16" [[package]] name = "thiserror" -version = "1.0.31" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.31" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" dependencies = [ "proc-macro2", "quote", @@ -727,9 +727,9 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "unicode-ident" -version = "1.0.0" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" [[package]] name = "unicode-xid" @@ -765,9 +765,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "winapi" diff --git a/Cargo.toml b/Cargo.toml index ae1d30a..540ba42 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,5 +2,5 @@ members = [ "rustcryptfs", "rustcryptfs-lib", - "rustcryptfs-linux" + "rustcryptfs-fuse" ] diff --git a/rustcryptfs-linux/Cargo.toml b/rustcryptfs-fuse/Cargo.toml similarity index 86% rename from rustcryptfs-linux/Cargo.toml rename to rustcryptfs-fuse/Cargo.toml index cbb3b6f..855d0e2 100644 --- a/rustcryptfs-linux/Cargo.toml +++ b/rustcryptfs-fuse/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "rustcryptfs-linux" +name = "rustcryptfs-fuse" version = "0.1.0" edition = "2021" diff --git a/rustcryptfs-linux/src/encrypted_filesystem.rs b/rustcryptfs-fuse/src/encrypted_filesystem.rs similarity index 99% rename from rustcryptfs-linux/src/encrypted_filesystem.rs rename to rustcryptfs-fuse/src/encrypted_filesystem.rs index 58616c5..1ada739 100644 --- a/rustcryptfs-linux/src/encrypted_filesystem.rs +++ b/rustcryptfs-fuse/src/encrypted_filesystem.rs @@ -130,9 +130,9 @@ impl EncryptedFs { let encrypted_name = dir_decoder.encrypt_filename(&name.to_string_lossy())?; - let encrypted_name = match encrypted_name { + let encrypted_name = match &encrypted_name { rustcryptfs_lib::filename::EncodedFilename::ShortFilename(s) => s, - rustcryptfs_lib::filename::EncodedFilename::LongFilename(l) => l.filename, + rustcryptfs_lib::filename::EncodedFilename::LongFilename(l) => l.filename(), }; let file_path = parent.join(encrypted_name); diff --git a/rustcryptfs-linux/src/error.rs b/rustcryptfs-fuse/src/error.rs similarity index 100% rename from rustcryptfs-linux/src/error.rs rename to rustcryptfs-fuse/src/error.rs diff --git a/rustcryptfs-linux/src/inode_cache.rs b/rustcryptfs-fuse/src/inode_cache.rs similarity index 100% rename from rustcryptfs-linux/src/inode_cache.rs rename to rustcryptfs-fuse/src/inode_cache.rs diff --git a/rustcryptfs-linux/src/lib.rs b/rustcryptfs-fuse/src/lib.rs similarity index 100% rename from rustcryptfs-linux/src/lib.rs rename to rustcryptfs-fuse/src/lib.rs diff --git a/rustcryptfs/Cargo.toml b/rustcryptfs/Cargo.toml index 189b0bb..a89647b 100644 --- a/rustcryptfs/Cargo.toml +++ b/rustcryptfs/Cargo.toml @@ -16,4 +16,4 @@ env_logger = "0.9.0" rpassword = "7.0.0" [target.'cfg(target_os = "linux")'.dependencies] -rustcryptfs-linux = { path = "../rustcryptfs-linux" } +rustcryptfs-fuse = { path = "../rustcryptfs-fuse" } diff --git a/rustcryptfs/src/main.rs b/rustcryptfs/src/main.rs index bbad968..5a0c2f0 100644 --- a/rustcryptfs/src/main.rs +++ b/rustcryptfs/src/main.rs @@ -118,7 +118,7 @@ fn decrypt_file(c: &DecryptCommand) -> anyhow::Result<()> { #[cfg(target_os = "linux")] fn mount(mount: &MountCommand) -> anyhow::Result<()> { use anyhow::Context; - use rustcryptfs_linux::EncryptedFs; + use rustcryptfs_fuse::EncryptedFs; let password = if let Some(password) = &mount.password { password.clone() From 94a3627a0f8f9e8e819cdaa70f09543ba1646bee Mon Sep 17 00:00:00 2001 From: oupson Date: Sat, 8 Oct 2022 23:51:06 +0200 Subject: [PATCH 34/36] Remove libfuse usage --- Cargo.lock | 7 ------- rustcryptfs-fuse/Cargo.toml | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4f3f80e..35b1648 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -257,7 +257,6 @@ dependencies = [ "log", "memchr", "page_size", - "pkg-config", "smallvec", "users", "zerocopy", @@ -434,12 +433,6 @@ dependencies = [ "digest", ] -[[package]] -name = "pkg-config" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" - [[package]] name = "polyval" version = "0.5.3" diff --git a/rustcryptfs-fuse/Cargo.toml b/rustcryptfs-fuse/Cargo.toml index 855d0e2..08e7cd0 100644 --- a/rustcryptfs-fuse/Cargo.toml +++ b/rustcryptfs-fuse/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -fuser = "0.11" +fuser = { version = "0.11", default-features = false } log = "0.4" rustcryptfs-lib = { path = "../rustcryptfs-lib" } thiserror = "1.0" From 198a75d0ee9563d2df98d5c146b47e0d8ad63a04 Mon Sep 17 00:00:00 2001 From: oupson Date: Sun, 9 Oct 2022 12:18:08 +0200 Subject: [PATCH 35/36] Mount as a feature --- Cargo.lock | 9 ++++++++- Cargo.toml | 3 ++- rustcryptfs-mount/Cargo.toml | 11 +++++++++++ rustcryptfs-mount/src/lib.rs | 14 ++++++++++++++ rustcryptfs/Cargo.toml | 8 +++++--- rustcryptfs/src/args.rs | 5 ++++- rustcryptfs/src/main.rs | 15 +++++++++------ 7 files changed, 53 insertions(+), 12 deletions(-) create mode 100644 rustcryptfs-mount/Cargo.toml create mode 100644 rustcryptfs-mount/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 35b1648..ff6880d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -532,8 +532,8 @@ dependencies = [ "env_logger", "log", "rpassword", - "rustcryptfs-fuse", "rustcryptfs-lib", + "rustcryptfs-mount", "serde", "serde_json", ] @@ -566,6 +566,13 @@ dependencies = [ "thiserror", ] +[[package]] +name = "rustcryptfs-mount" +version = "0.1.0" +dependencies = [ + "rustcryptfs-fuse", +] + [[package]] name = "ryu" version = "1.0.11" diff --git a/Cargo.toml b/Cargo.toml index 540ba42..4edd13b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,5 +2,6 @@ members = [ "rustcryptfs", "rustcryptfs-lib", - "rustcryptfs-fuse" + "rustcryptfs-fuse", + "rustcryptfs-mount" ] diff --git a/rustcryptfs-mount/Cargo.toml b/rustcryptfs-mount/Cargo.toml new file mode 100644 index 0000000..fc3e0af --- /dev/null +++ b/rustcryptfs-mount/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rustcryptfs-mount" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +[target.'cfg(target_os = "linux")'.dependencies] +rustcryptfs-fuse = { path = "../rustcryptfs-fuse" } diff --git a/rustcryptfs-mount/src/lib.rs b/rustcryptfs-mount/src/lib.rs new file mode 100644 index 0000000..7a51b40 --- /dev/null +++ b/rustcryptfs-mount/src/lib.rs @@ -0,0 +1,14 @@ +use std::path::Path; + +use rustcryptfs_fuse::EncryptedFs; + +#[cfg(target_os = "linux")] +pub fn mount

(path: P, mount_point: P, password: &str) -> rustcryptfs_fuse::error::Result<()> +where + P: AsRef, +{ + let fs = EncryptedFs::new(path, password)?; + + fs.mount(mount_point)?; + Ok(()) +} diff --git a/rustcryptfs/Cargo.toml b/rustcryptfs/Cargo.toml index a89647b..4db0ef5 100644 --- a/rustcryptfs/Cargo.toml +++ b/rustcryptfs/Cargo.toml @@ -5,6 +5,10 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +default = ["mount"] +mount = ["rustcryptfs-mount"] + [dependencies] anyhow = "1.0.53" serde = { version = "1.0.136", features = ["derive"] } @@ -14,6 +18,4 @@ log = "0.4.17" rustcryptfs-lib = { path = "../rustcryptfs-lib" } env_logger = "0.9.0" rpassword = "7.0.0" - -[target.'cfg(target_os = "linux")'.dependencies] -rustcryptfs-fuse = { path = "../rustcryptfs-fuse" } +rustcryptfs-mount = { path = "../rustcryptfs-mount", optional = true } \ No newline at end of file diff --git a/rustcryptfs/src/args.rs b/rustcryptfs/src/args.rs index 44d66e5..7cc85e8 100644 --- a/rustcryptfs/src/args.rs +++ b/rustcryptfs/src/args.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "mount")] use std::path::PathBuf; use clap::{Parser, Subcommand}; @@ -14,9 +15,10 @@ pub(crate) enum Commands { /// Decrypt a file Decrypt(DecryptCommand), - // List file contained in a directory + /// List file contained in a directory Ls(LsCommand), + #[cfg(feature = "mount")] /// Mount an encrypted folder Mount(MountCommand), } @@ -49,6 +51,7 @@ pub(crate) struct LsCommand { pub(crate) password : Option } +#[cfg(feature = "mount")] #[derive(Debug, Parser)] pub(crate) struct MountCommand { /// The directory diff --git a/rustcryptfs/src/main.rs b/rustcryptfs/src/main.rs index 5a0c2f0..2b99749 100644 --- a/rustcryptfs/src/main.rs +++ b/rustcryptfs/src/main.rs @@ -6,19 +6,22 @@ use std::{ use clap::Parser; -use args::{DecryptCommand, LsCommand, MountCommand}; +use args::{DecryptCommand, LsCommand}; use rustcryptfs_lib::GocryptFs; +#[cfg(feature = "mount")] +use args::MountCommand; + mod args; fn main() -> anyhow::Result<()> { env_logger::init(); let args = args::Args::parse(); - log::debug!("{:?}", args); match &args.command { args::Commands::Decrypt(c) => decrypt_file(c), args::Commands::Ls(c) => ls(c), + #[cfg(feature = "mount")] args::Commands::Mount(c) => mount(c), } } @@ -116,9 +119,9 @@ fn decrypt_file(c: &DecryptCommand) -> anyhow::Result<()> { } #[cfg(target_os = "linux")] +#[cfg(feature = "mount")] fn mount(mount: &MountCommand) -> anyhow::Result<()> { use anyhow::Context; - use rustcryptfs_fuse::EncryptedFs; let password = if let Some(password) = &mount.password { password.clone() @@ -126,14 +129,14 @@ fn mount(mount: &MountCommand) -> anyhow::Result<()> { rpassword::prompt_password("Your password: ")? }; - let fs = EncryptedFs::new(&mount.path, &password)?; - - fs.mount(&mount.mountpoint) + rustcryptfs_mount::mount(&mount.path, &mount.mountpoint, &password) .context("Failed to run fuse fs")?; + Ok(()) } #[cfg(not(target_os = "linux"))] +#[cfg(feature = "mount")] fn mount(mount: &MountCommand) -> anyhow::Result<()> { unimplemented!() } From 0aa87c1f53fd025fa7c26a7bc64f6befb51b42ec Mon Sep 17 00:00:00 2001 From: oupson Date: Sun, 9 Oct 2022 12:43:26 +0200 Subject: [PATCH 36/36] Change error message and info for user --- rustcryptfs-fuse/src/encrypted_filesystem.rs | 6 +++--- rustcryptfs/src/main.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rustcryptfs-fuse/src/encrypted_filesystem.rs b/rustcryptfs-fuse/src/encrypted_filesystem.rs index 1ada739..7f5f5e1 100644 --- a/rustcryptfs-fuse/src/encrypted_filesystem.rs +++ b/rustcryptfs-fuse/src/encrypted_filesystem.rs @@ -47,7 +47,7 @@ impl EncryptedFs { log::info!("Opening dir ..."); let fs = GocryptFs::open(path, password)?; - log::info!("Done"); + println!("Filesystem mounted and ready."); let mut inode_cache = BTreeMap::new(); inode_cache.insert(FUSE_ROOT_ID, path.to_path_buf()); @@ -307,7 +307,7 @@ impl Filesystem for EncryptedFs { match self.lookup_impl(parent, name) { Ok((ttl, attr, generation)) => reply.entry(&ttl, &attr, generation), Err(e) => { - log::error!("lookup : {}", e); + log::debug!("error on lookup : {}", e); reply.error(e.to_raw_code()) } } @@ -324,7 +324,7 @@ impl Filesystem for EncryptedFs { match self.read_dir_impl(ino, offset, &mut reply) { Ok(()) => reply.ok(), Err(e) => { - log::error!("readdir : {}", e); + log::debug!("error on readdir : {}", e); reply.error(e.to_raw_code()) } } diff --git a/rustcryptfs/src/main.rs b/rustcryptfs/src/main.rs index 2b99749..2e70937 100644 --- a/rustcryptfs/src/main.rs +++ b/rustcryptfs/src/main.rs @@ -51,7 +51,7 @@ fn ls(c: &LsCommand) -> anyhow::Result<()> { for dir in std::fs::read_dir(folder_path)?.flat_map(|e| e.ok()) { let filename = dir.file_name(); - let filename = filename.to_str().unwrap(); + let filename = filename.to_string_lossy(); if filename != "gocryptfs.conf" && filename != "gocryptfs.diriv" { if filename.starts_with("gocryptfs.longname.") { @@ -62,7 +62,7 @@ fn ls(c: &LsCommand) -> anyhow::Result<()> { println!("{}", res); } } - } else if let Ok(res) = dir_decoder.decode_filename(filename) { + } else if let Ok(res) = dir_decoder.decode_filename(&*filename) { println!("{}", res); } } @@ -88,7 +88,7 @@ fn decrypt_file(c: &DecryptCommand) -> anyhow::Result<()> { &password, )?; - let mut file = File::open(file_path).unwrap(); + let mut file = File::open(file_path)?; let enc = fs.content_decoder();