crypto: Properly handle errors in the pickle key decryption.

master
Damir Jelić 2020-10-21 15:28:43 +02:00
parent d175c47a05
commit ac0df5dea9
3 changed files with 28 additions and 16 deletions

View File

@ -308,6 +308,10 @@ pub enum CryptoStoreError {
#[error(transparent)] #[error(transparent)]
SessionUnpickling(#[from] SessionUnpicklingError), SessionUnpickling(#[from] SessionUnpicklingError),
/// Failed to decrypt an pickled object.
#[error("An object failed to be decrypted while unpickling")]
UnpicklingError,
/// A Matirx identifier failed to be validated. /// A Matirx identifier failed to be validated.
#[error(transparent)] #[error(transparent)]
IdentifierValidation(#[from] IdentifierValidationError), IdentifierValidation(#[from] IdentifierValidationError),

View File

@ -16,7 +16,7 @@ use std::convert::TryFrom;
use aes_gcm::{ use aes_gcm::{
aead::{generic_array::GenericArray, Aead, NewAead}, aead::{generic_array::GenericArray, Aead, NewAead},
Aes256Gcm, Aes256Gcm, Error as DecryptionError,
}; };
use getrandom::getrandom; use getrandom::getrandom;
use hmac::Hmac; use hmac::Hmac;
@ -58,6 +58,18 @@ pub struct PickleKey {
aes256_key: Vec<u8>, aes256_key: Vec<u8>,
} }
impl Default for PickleKey {
fn default() -> Self {
let mut key = vec![0u8; KEY_SIZE];
getrandom(&mut key).expect("Can't generate new pickle key");
Self {
version: VERSION,
aes256_key: key,
}
}
}
impl TryFrom<Vec<u8>> for PickleKey { impl TryFrom<Vec<u8>> for PickleKey {
type Error = (); type Error = ();
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> { fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
@ -75,13 +87,7 @@ impl TryFrom<Vec<u8>> for PickleKey {
impl PickleKey { impl PickleKey {
/// Generate a new random pickle key. /// Generate a new random pickle key.
pub fn new() -> Self { pub fn new() -> Self {
let mut key = vec![0u8; KEY_SIZE]; Default::default()
getrandom(&mut key).expect("Can't generate new pickle key");
Self {
version: VERSION,
aes256_key: key,
}
} }
fn expand_key(passphrase: &str, salt: &[u8]) -> Zeroizing<Vec<u8>> { fn expand_key(passphrase: &str, salt: &[u8]) -> Zeroizing<Vec<u8>> {
@ -137,20 +143,21 @@ impl PickleKey {
/// pickle key. /// pickle key.
/// ///
/// * `encrypted` - The exported and encrypted version of the pickle key. /// * `encrypted` - The exported and encrypted version of the pickle key.
pub fn from_encrypted(passphrase: &str, encrypted: EncryptedPickleKey) -> Self { pub fn from_encrypted(
passphrase: &str,
encrypted: EncryptedPickleKey,
) -> Result<Self, DecryptionError> {
let key = PickleKey::expand_key(passphrase, &encrypted.kdf_salt); let key = PickleKey::expand_key(passphrase, &encrypted.kdf_salt);
let key = GenericArray::from_slice(key.as_ref()); let key = GenericArray::from_slice(key.as_ref());
let cipher = Aes256Gcm::new(&key); let cipher = Aes256Gcm::new(&key);
let nonce = GenericArray::from_slice(&encrypted.nonce); let nonce = GenericArray::from_slice(&encrypted.nonce);
let decrypted_key = cipher let decrypted_key = cipher.decrypt(nonce, encrypted.ciphertext.as_ref())?;
.decrypt(nonce, encrypted.ciphertext.as_ref())
.expect("Can't decrypt pickle");
Self { Ok(Self {
version: encrypted.version, version: encrypted.version,
aes256_key: decrypted_key, aes256_key: decrypted_key,
} })
} }
} }
@ -169,7 +176,7 @@ mod test {
let pickle_key = PickleKey::new(); let pickle_key = PickleKey::new();
let encrypted = pickle_key.encrypt(passphrase); let encrypted = pickle_key.encrypt(passphrase);
let decrypted = PickleKey::from_encrypted(passphrase, encrypted); let decrypted = PickleKey::from_encrypted(passphrase, encrypted).unwrap();
assert_eq!(pickle_key, decrypted); assert_eq!(pickle_key, decrypted);
} }

View File

@ -516,8 +516,9 @@ impl SqliteStore {
.await?; .await?;
Ok(if let Some(row) = row { Ok(if let Some(row) = row {
let encrypted: EncryptedPickleKey = serde_json::from_str(&row.0).unwrap(); let encrypted: EncryptedPickleKey = serde_json::from_str(&row.0)?;
PickleKey::from_encrypted(passphrase, encrypted) PickleKey::from_encrypted(passphrase, encrypted)
.map_err(|_| CryptoStoreError::UnpicklingError)?
} else { } else {
let key = PickleKey::new(); let key = PickleKey::new();
let encrypted = key.encrypt(passphrase); let encrypted = key.encrypt(passphrase);