Error related rustcryptfs-lib refracto

This commit is contained in:
oupson 2022-10-08 16:10:43 +02:00
parent 965c07df0a
commit c57f9b3a85
Signed by: oupson
GPG Key ID: 3BD88615552EFCB7
10 changed files with 105 additions and 79 deletions

View File

@ -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<aes_gcm::Error> 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),
}

View File

@ -9,7 +9,9 @@ use aes_gcm::{
}; };
use hkdf::Hkdf; 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. /// An enum that contain all the feature flag a gocryptfs config can have.
#[derive(serde::Deserialize, Debug, PartialEq, Eq, Hash)] #[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). /// 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) /// ![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 block = base64::decode(&self.encrypted_key)?;
let key = self.scrypt_object.get_hkdf_key(password)?; let key = self.scrypt_object.get_hkdf_key(password)?;
@ -77,7 +79,9 @@ impl CryptConf {
let tag = &block[block.len() - 16..]; let tag = &block[block.len() - 16..];
let ciphertext = &block[16..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::<Aes256, cipher::consts::U16>::new(Key::from_slice(&key)); let aes = AesGcm::<Aes256, cipher::consts::U16>::new(Key::from_slice(&key));
@ -133,19 +137,14 @@ pub struct ScryptObject {
} }
impl ScryptObject { impl ScryptObject {
fn get_hkdf_key(&self, password: &[u8]) -> std::result::Result<Vec<u8>, FilenameDecryptError> { fn get_hkdf_key(&self, password: &[u8]) -> Result<Vec<u8>, ConfigError> {
let mut key = [0u8; 32]; let mut key = [0u8; 32];
let params = scrypt::Params::new((self.n as f64).log2() as u8, self.r, self.p) let params = scrypt::Params::new((self.n as f64).log2() as u8, self.r, self.p)
.map_err(|e| ScryptError::from(e))?; .map_err(|e| ScryptError::from(e))?;
scrypt::scrypt( scrypt::scrypt(password, &base64::decode(&self.salt)?, &params, &mut key)
password, .map_err(|e| ScryptError::from(e))?;
&base64::decode(&self.salt).unwrap(),
&params,
&mut key,
)
.map_err(|e| ScryptError::from(e))?;
let hdkf = Hkdf::<sha2::Sha256>::new(None, &key); let hdkf = Hkdf::<sha2::Sha256>::new(None, &key);
hdkf.expand(b"AES-GCM file content encryption", &mut key)?; hdkf.expand(b"AES-GCM file content encryption", &mut key)?;

View File

@ -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<aes_gcm::Error> for ContentCipherError {
fn from(_: aes_gcm::Error) -> Self {
Self::ContentDecryptError()
}
}

View File

@ -4,7 +4,9 @@ use aes_gcm::{aead::generic_array::GenericArray, aes::Aes256, AeadInPlace, AesGc
use cipher::consts::{U16, U32}; use cipher::consts::{U16, U32};
use hkdf::Hkdf; use hkdf::Hkdf;
use crate::error::{DecryptError, Result}; mod error;
pub use error::*;
type Aes256Gcm = AesGcm<Aes256, U16>; type Aes256Gcm = AesGcm<Aes256, U16>;
@ -16,16 +18,15 @@ pub struct ContentEnc {
impl ContentEnc { impl ContentEnc {
/// Init a new ContentEnc from the master key and the iv len. /// 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<Self, ContentCipherError> {
let mut key = [0u8; 32]; let mut key = [0u8; 32];
let hdkf = Hkdf::<sha2::Sha256>::new(None, &master_key); let hdkf = Hkdf::<sha2::Sha256>::new(None, &master_key);
hdkf.expand(b"AES-GCM file content encryption", &mut key) hdkf.expand(b"AES-GCM file content encryption", &mut key)?;
.unwrap();
Self { Ok(Self {
key: GenericArray::from(key), key: GenericArray::from(key),
iv_len: iv_len as usize, 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. /// 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: &[u8],
block_number: u64, block_number: u64,
file_id: Option<&[u8]>, file_id: Option<&[u8]>,
) -> Result<Vec<u8>> { ) -> Result<Vec<u8>, ContentCipherError> {
// TODO NOT BOX // TODO NOT BOX
if block.len() == 0 { if block.len() == 0 {
return Ok(block.into()); return Ok(block.into());
@ -45,7 +46,7 @@ impl ContentEnc {
} }
if block.len() < self.iv_len { if block.len() < self.iv_len {
return Err(DecryptError::BlockTooShort().into()); return Err(ContentCipherError::BlockTooShort().into());
} }
let nonce = &block[..self.iv_len]; let nonce = &block[..self.iv_len];
@ -53,7 +54,7 @@ impl ContentEnc {
let ciphertext = &block[self.iv_len..block.len() - self.iv_len]; let ciphertext = &block[self.iv_len..block.len() - self.iv_len];
if nonce.iter().all(|f| *f == 0) { if nonce.iter().all(|f| *f == 0) {
return Err(DecryptError::AllZeroNonce().into()); return Err(ContentCipherError::AllZeroNonce().into());
} }
let mut buf = Vec::from(ciphertext); let mut buf = Vec::from(ciphertext);

View File

@ -1,49 +1,19 @@
use thiserror::Error; use thiserror::Error;
use crate::{config::ConfigError, content::ContentCipherError, filename::FilenameCipherError};
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum 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)] #[error(transparent)]
DecodeError(#[from] DecryptError), FilenameCipherError(#[from] FilenameCipherError),
}
impl From<aes_gcm::Error> 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 {
#[error(transparent)] #[error(transparent)]
ScryptError(#[from] ScryptError), ContentCipherError(#[from] ContentCipherError),
#[error("Failed to decode base64")]
Base64Error(#[from] base64::DecodeError),
#[error(transparent)] #[error(transparent)]
HdkfError(#[from] hkdf::InvalidLength), ConfigError(#[from] ConfigError),
#[error("Failed to decrypt filename")] #[error(transparent)]
DecryptError(), JsonError(#[from] serde_json::Error),
} #[error(transparent)]
IoError(#[from] std::io::Error),
#[derive(Debug, Error)]
pub enum ScryptError {
#[error(transparent)]
InvalidParams(#[from] scrypt::errors::InvalidParams),
#[error(transparent)]
InvalidOutputLen(#[from] scrypt::errors::InvalidOutputLen),
} }

View File

@ -1,7 +1,6 @@
use crate::error::FilenameDecryptError; use cipher::{block_padding::Pkcs7, Iv, Key, KeyIvInit};
use cipher::{block_padding::Pkcs7, inout::InOutBufReserved, Iv, Key, KeyIvInit};
use super::{EmeCipher, EncodedFilename, IntoDecodable}; use super::{EmeCipher, EncodedFilename, FilenameCipherError, IntoDecodable};
pub struct DirFilenameCipher<'a, 'b> { pub struct DirFilenameCipher<'a, 'b> {
filename_key: &'a Key<EmeCipher>, filename_key: &'a Key<EmeCipher>,
@ -13,7 +12,7 @@ impl<'a, 'b> DirFilenameCipher<'a, 'b> {
Self { filename_key, iv } Self { filename_key, iv }
} }
pub fn decode_filename<S>(&self, name: S) -> Result<String, FilenameDecryptError> pub fn decode_filename<S>(&self, name: S) -> Result<String, FilenameCipherError>
where where
S: IntoDecodable, 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 mut filename = base64::decode_config(name.to_decodable(), base64::URL_SAFE_NO_PAD)?;
let filename_decoded = cipher let filename_decoded = cipher
.decrypt_padded_mut::<Pkcs7>(&mut filename) .decrypt_padded_mut::<Pkcs7>(&mut filename)
.map_err(|_| FilenameDecryptError::DecryptError())?; .map_err(|_| FilenameCipherError::DecryptError())?;
Ok(String::from_utf8_lossy(filename_decoded).to_string()) Ok(String::from_utf8_lossy(filename_decoded).to_string())
} }
@ -30,17 +29,13 @@ impl<'a, 'b> DirFilenameCipher<'a, 'b> {
pub fn encrypt_filename( pub fn encrypt_filename(
&self, &self,
plain_text_name: &str, plain_text_name: &str,
) -> Result<EncodedFilename, FilenameDecryptError> { ) -> Result<EncodedFilename, FilenameCipherError> {
let mut cipher = EmeCipher::new(self.filename_key, self.iv); let mut cipher = EmeCipher::new(self.filename_key, self.iv);
let mut res = [0u8; 2048]; let mut res = [0u8; 2048];
let filename_encrypted = cipher let filename_encrypted = cipher
.encrypt_padded_inout_mut::<Pkcs7>( .encrypt_padded_b2b_mut::<Pkcs7>(plain_text_name.as_bytes(), &mut res)
InOutBufReserved::from_slices(plain_text_name.as_bytes(), &mut res).unwrap(), .map_err(|_| FilenameCipherError::EncryptError())?;
)
.map_err(|_| FilenameDecryptError::DecryptError())?; // TODO RENAME ERROR
// TODO LONG FILENAME
let filename = base64::encode_config(filename_encrypted, base64::URL_SAFE_NO_PAD); let filename = base64::encode_config(filename_encrypted, base64::URL_SAFE_NO_PAD);

View File

@ -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()
}

View File

@ -3,22 +3,22 @@ use cipher::{Iv, Key};
use eme_mode::DynamicEme; use eme_mode::DynamicEme;
use hkdf::Hkdf; use hkdf::Hkdf;
use crate::error::FilenameDecryptError;
pub(crate) type EmeCipher = DynamicEme<Aes256>; pub(crate) type EmeCipher = DynamicEme<Aes256>;
mod dir_filename_cipher; mod dir_filename_cipher;
mod filename_encoded; mod filename_encoded;
mod error;
pub use dir_filename_cipher::*; pub use dir_filename_cipher::*;
pub use filename_encoded::*; pub use filename_encoded::*;
pub use error::*;
pub struct FilenameCipher { pub struct FilenameCipher {
filename_key: Key<Aes256>, filename_key: Key<Aes256>,
} }
impl FilenameCipher { impl FilenameCipher {
pub fn new(master_key: &[u8]) -> Result<Self, FilenameDecryptError> { pub fn new(master_key: &[u8]) -> Result<Self, FilenameCipherError> {
let mut key = [0u8; 32]; let mut key = [0u8; 32];
let hdkf = Hkdf::<sha2::Sha256>::new(None, &master_key); let hdkf = Hkdf::<sha2::Sha256>::new(None, &master_key);
hdkf.expand(b"EME filename encryption", &mut key)?; hdkf.expand(b"EME filename encryption", &mut key)?;

View File

@ -27,7 +27,7 @@ impl GocryptFs {
let base_path = encrypted_dir_path.as_ref(); let base_path = encrypted_dir_path.as_ref();
let mut config_file = 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()) Self::load_from_reader(&mut config_file, password.as_bytes())
} }
@ -39,13 +39,12 @@ impl GocryptFs {
where where
R: Read, R: Read,
{ {
let config = serde_json::from_reader::<_, config::CryptConf>(reader_config) let config = serde_json::from_reader::<_, config::CryptConf>(reader_config)?;
.expect("failed to parse config");
let master_key = config.get_master_key(password)?; let master_key = config.get_master_key(password)?;
let filename_decoder = FilenameCipher::new(&master_key)?; 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 { Ok(Self {
filename_decoder, filename_decoder,

View File

@ -1,3 +1,4 @@
use rustcryptfs_lib::filename::FilenameCipherError;
use thiserror::Error; use thiserror::Error;
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
@ -11,5 +12,5 @@ pub enum Error {
RustCryptFsError(#[from] rustcryptfs_lib::error::Error), RustCryptFsError(#[from] rustcryptfs_lib::error::Error),
#[error(transparent)] #[error(transparent)]
RustCryptFsFilenameError(#[from] rustcryptfs_lib::error::FilenameDecryptError), RustCryptFsFilenameError(#[from] FilenameCipherError),
} }