From 8c869f26f1ffeb56f122af440569ebbdb63f3db1 Mon Sep 17 00:00:00 2001 From: Hinton Date: Fri, 19 Jan 2024 14:40:54 +0100 Subject: [PATCH] Explore introducing a Decrypted struct --- Cargo.lock | 15 +++++++++ crates/bitwarden-crypto/Cargo.toml | 1 + crates/bitwarden-crypto/src/decrypted.rs | 32 +++++++++++++++++++ .../src/enc_string/symmetric.rs | 26 +++++++-------- crates/bitwarden-crypto/src/lib.rs | 2 ++ 5 files changed, 63 insertions(+), 13 deletions(-) create mode 100644 crates/bitwarden-crypto/src/decrypted.rs diff --git a/Cargo.lock b/Cargo.lock index 960a7707f..bfbb5cbb0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -445,6 +445,7 @@ dependencies = [ "thiserror", "uniffi", "uuid", + "zeroize", ] [[package]] @@ -4339,6 +4340,20 @@ name = "zeroize" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.47", +] [[package]] name = "zxcvbn" diff --git a/crates/bitwarden-crypto/Cargo.toml b/crates/bitwarden-crypto/Cargo.toml index ddcaceb06..b04e993ad 100644 --- a/crates/bitwarden-crypto/Cargo.toml +++ b/crates/bitwarden-crypto/Cargo.toml @@ -39,6 +39,7 @@ subtle = ">=2.5.0, <3.0" thiserror = ">=1.0.40, <2.0" uniffi = { version = "=0.25.2", optional = true } uuid = { version = ">=1.3.3, <2.0", features = ["serde"] } +zeroize = { version = ">=1.7.0, <2.0", features = ["zeroize_derive"] } [dev-dependencies] rand_chacha = "0.3.1" diff --git a/crates/bitwarden-crypto/src/decrypted.rs b/crates/bitwarden-crypto/src/decrypted.rs new file mode 100644 index 000000000..c218aee22 --- /dev/null +++ b/crates/bitwarden-crypto/src/decrypted.rs @@ -0,0 +1,32 @@ +use zeroize::{Zeroize, ZeroizeOnDrop}; + +use crate::CryptoError; + +#[derive(Zeroize, ZeroizeOnDrop)] +pub struct Decrypted { + value: V, +} + +impl Decrypted { + pub fn new(value: V) -> Self { + Self { value } + } + + pub fn expose(&self) -> &V { + &self.value + } +} + +impl TryFrom>> for Decrypted { + type Error = CryptoError; + + fn try_from(v: Decrypted>) -> Result { + let mut str = v.expose().to_owned(); + + let rtn = String::from_utf8(str).map_err(|_| CryptoError::InvalidUtf8String); + + str.zeroize(); + + rtn.map(Decrypted::new) + } +} diff --git a/crates/bitwarden-crypto/src/enc_string/symmetric.rs b/crates/bitwarden-crypto/src/enc_string/symmetric.rs index d6dd44374..b9e4ee9e9 100644 --- a/crates/bitwarden-crypto/src/enc_string/symmetric.rs +++ b/crates/bitwarden-crypto/src/enc_string/symmetric.rs @@ -7,7 +7,7 @@ use serde::Deserialize; use super::{check_length, from_b64, from_b64_vec, split_enc_string}; use crate::{ error::{CryptoError, EncStringParseError, Result}, - KeyDecryptable, KeyEncryptable, LocateKey, SymmetricCryptoKey, + Decrypted, KeyDecryptable, KeyEncryptable, LocateKey, SymmetricCryptoKey, }; /// # Encrypted string primitive @@ -228,13 +228,13 @@ impl KeyEncryptable for &[u8] { } } -impl KeyDecryptable> for EncString { - fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result> { +impl KeyDecryptable>> for EncString { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result>> { match self { EncString::AesCbc256_HmacSha256_B64 { iv, mac, data } => { let mac_key = key.mac_key.ok_or(CryptoError::InvalidMac)?; let dec = crate::aes::decrypt_aes256_hmac(iv, mac, data.clone(), mac_key, key.key)?; - Ok(dec) + Ok(Decrypted::new(dec)) } _ => Err(CryptoError::InvalidKey), } @@ -247,10 +247,10 @@ impl KeyEncryptable for String { } } -impl KeyDecryptable for EncString { - fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result { - let dec: Vec = self.decrypt_with_key(key)?; - String::from_utf8(dec).map_err(|_| CryptoError::InvalidUtf8String) +impl KeyDecryptable> for EncString { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result> { + let dec: Decrypted> = self.decrypt_with_key(key)?; + dec.try_into() } } @@ -269,17 +269,17 @@ impl schemars::JsonSchema for EncString { #[cfg(test)] mod tests { use super::EncString; - use crate::{derive_symmetric_key, KeyDecryptable, KeyEncryptable}; + use crate::{derive_symmetric_key, Decrypted, KeyDecryptable, KeyEncryptable}; #[test] fn test_enc_string_roundtrip() { let key = derive_symmetric_key("test"); - let test_string = "encrypted_test_string".to_string(); - let cipher = test_string.clone().encrypt_with_key(&key).unwrap(); + let test_string = "encrypted_test_string"; + let cipher = test_string.to_owned().encrypt_with_key(&key).unwrap(); - let decrypted_str: String = cipher.decrypt_with_key(&key).unwrap(); - assert_eq!(decrypted_str, test_string); + let decrypted_str: Decrypted = cipher.decrypt_with_key(&key).unwrap(); + assert_eq!(decrypted_str.expose(), test_string); } #[test] diff --git a/crates/bitwarden-crypto/src/lib.rs b/crates/bitwarden-crypto/src/lib.rs index 3c1aced24..2d4b5aa9b 100644 --- a/crates/bitwarden-crypto/src/lib.rs +++ b/crates/bitwarden-crypto/src/lib.rs @@ -40,6 +40,8 @@ pub use util::generate_random_bytes; mod wordlist; pub use util::pbkdf2; pub use wordlist::EFF_LONG_WORD_LIST; +mod decrypted; +pub use decrypted::Decrypted; #[cfg(feature = "mobile")] uniffi::setup_scaffolding!();