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), }