Error related rustcryptfs-lib refracto
This commit is contained in:
parent
965c07df0a
commit
c57f9b3a85
|
@ -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),
|
||||||
|
}
|
|
@ -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,18 +137,13 @@ 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)?, ¶ms, &mut key)
|
||||||
password,
|
|
||||||
&base64::decode(&self.salt).unwrap(),
|
|
||||||
¶ms,
|
|
||||||
&mut key,
|
|
||||||
)
|
|
||||||
.map_err(|e| ScryptError::from(e))?;
|
.map_err(|e| ScryptError::from(e))?;
|
||||||
|
|
||||||
let hdkf = Hkdf::<sha2::Sha256>::new(None, &key);
|
let hdkf = Hkdf::<sha2::Sha256>::new(None, &key);
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
|
@ -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),
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
|
@ -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)?;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue