From 59c044a62489b291b2463c8f44725848335de86b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garci=CC=81a?= Date: Thu, 19 Oct 2023 16:55:02 +0200 Subject: [PATCH 1/3] Split Encryptable/Decryptable trait into encryption and key retrieval --- .../bitwarden/src/auth/login/access_token.rs | 4 +- .../src/client/encryption_settings.rs | 29 ++--- crates/bitwarden/src/crypto/enc_string.rs | 44 +++++--- crates/bitwarden/src/crypto/encryptable.rs | 47 ++++---- .../bitwarden/src/crypto/key_encryptable.rs | 69 ++++++++++++ crates/bitwarden/src/crypto/master_key.rs | 6 +- crates/bitwarden/src/crypto/mod.rs | 4 +- .../src/mobile/vault/client_sends.rs | 22 ++-- .../bitwarden/src/vault/cipher/attachment.rs | 20 ++-- crates/bitwarden/src/vault/cipher/card.rs | 36 +++--- crates/bitwarden/src/vault/cipher/cipher.rs | 99 ++++++++++------- crates/bitwarden/src/vault/cipher/field.rs | 20 ++-- crates/bitwarden/src/vault/cipher/identity.rs | 84 +++++++------- .../bitwarden/src/vault/cipher/local_data.rs | 12 +- crates/bitwarden/src/vault/cipher/login.rs | 40 ++++--- .../bitwarden/src/vault/cipher/secure_note.rs | 12 +- crates/bitwarden/src/vault/collection.rs | 19 +++- crates/bitwarden/src/vault/folder.rs | 17 +-- .../bitwarden/src/vault/password_history.rs | 22 ++-- crates/bitwarden/src/vault/send.rs | 103 ++++++++---------- 20 files changed, 389 insertions(+), 320 deletions(-) create mode 100644 crates/bitwarden/src/crypto/key_encryptable.rs diff --git a/crates/bitwarden/src/auth/login/access_token.rs b/crates/bitwarden/src/auth/login/access_token.rs index 46fa35779..e97efb265 100644 --- a/crates/bitwarden/src/auth/login/access_token.rs +++ b/crates/bitwarden/src/auth/login/access_token.rs @@ -10,7 +10,7 @@ use crate::{ login::{response::two_factor::TwoFactorProviders, PasswordLoginResponse}, }, client::{AccessToken, LoginMethod, ServiceAccountLoginMethod}, - crypto::{EncString, SymmetricCryptoKey}, + crypto::{EncString, KeyDecryptable, SymmetricCryptoKey}, error::{Error, Result}, util::{decode_token, BASE64_ENGINE}, Client, @@ -31,7 +31,7 @@ pub(crate) async fn access_token_login( // Extract the encrypted payload and use the access token encryption key to decrypt it let payload = EncString::from_str(&r.encrypted_payload)?; - let decrypted_payload = payload.decrypt_with_key(&access_token.encryption_key)?; + let decrypted_payload: Vec = payload.decrypt_with_key(&access_token.encryption_key)?; // Once decrypted, we have to JSON decode to extract the organization encryption key #[derive(serde::Deserialize)] diff --git a/crates/bitwarden/src/client/encryption_settings.rs b/crates/bitwarden/src/client/encryption_settings.rs index 9c79a1781..83a4f87ea 100644 --- a/crates/bitwarden/src/client/encryption_settings.rs +++ b/crates/bitwarden/src/client/encryption_settings.rs @@ -9,7 +9,7 @@ use { }; use crate::{ - crypto::{encrypt_aes256_hmac, EncString, SymmetricCryptoKey}, + crypto::{encrypt_aes256_hmac, EncString, KeyDecryptable, SymmetricCryptoKey}, error::{CryptoError, Result}, }; @@ -46,7 +46,7 @@ impl EncryptionSettings { // Decrypt the private key with the user key let private_key = { - let dec = private_key.decrypt_with_key(&user_key)?; + let dec: Vec = private_key.decrypt_with_key(&user_key)?; Some( rsa::RsaPrivateKey::from_pkcs8_der(&dec) .map_err(|_| CryptoError::InvalidKey)?, @@ -98,7 +98,7 @@ impl EncryptionSettings { Ok(self) } - fn get_key(&self, org_id: &Option) -> Option<&SymmetricCryptoKey> { + pub(crate) fn get_key(&self, org_id: &Option) -> Option<&SymmetricCryptoKey> { // If we don't have a private key set (to decode multiple org keys), we just use the main user key if self.private_key.is_none() { return Some(&self.user_key); @@ -110,20 +110,6 @@ impl EncryptionSettings { } } - pub(crate) fn decrypt_bytes( - &self, - cipher: &EncString, - org_id: &Option, - ) -> Result> { - let key = self.get_key(org_id).ok_or(CryptoError::NoKeyForOrg)?; - cipher.decrypt_with_key(key) - } - - pub(crate) fn decrypt(&self, cipher: &EncString, org_id: &Option) -> Result { - let dec = self.decrypt_bytes(cipher, org_id)?; - String::from_utf8(dec).map_err(|_| CryptoError::InvalidUtf8String.into()) - } - pub(crate) fn encrypt(&self, data: &[u8], org_id: &Option) -> Result { let key = self.get_key(org_id).ok_or(CryptoError::NoKeyForOrg)?; @@ -134,18 +120,17 @@ impl EncryptionSettings { #[cfg(test)] mod tests { - use super::{EncryptionSettings, SymmetricCryptoKey}; - use crate::crypto::{Decryptable, Encryptable}; + use super::SymmetricCryptoKey; + use crate::crypto::{KeyDecryptable, KeyEncryptable}; #[test] fn test_encryption_settings() { let key = SymmetricCryptoKey::generate("test"); - let settings = EncryptionSettings::new_single_key(key); let test_string = "encrypted_test_string".to_string(); - let cipher = test_string.clone().encrypt(&settings, &None).unwrap(); + let cipher = test_string.clone().encrypt_with_key(&key).unwrap(); - let decrypted_str = cipher.decrypt(&settings, &None).unwrap(); + let decrypted_str: String = cipher.decrypt_with_key(&key).unwrap(); assert_eq!(decrypted_str, test_string); } } diff --git a/crates/bitwarden/src/crypto/enc_string.rs b/crates/bitwarden/src/crypto/enc_string.rs index b701aaf8f..4d71696db 100644 --- a/crates/bitwarden/src/crypto/enc_string.rs +++ b/crates/bitwarden/src/crypto/enc_string.rs @@ -2,15 +2,15 @@ use std::{fmt::Display, str::FromStr}; use base64::Engine; use serde::{de::Visitor, Deserialize}; -use uuid::Uuid; use crate::{ - client::encryption_settings::EncryptionSettings, - crypto::{decrypt_aes256_hmac, Decryptable, Encryptable, SymmetricCryptoKey}, + crypto::{decrypt_aes256_hmac, SymmetricCryptoKey}, error::{CryptoError, EncStringParseError, Error, Result}, util::BASE64_ENGINE, }; +use super::{KeyDecryptable, KeyEncryptable, LocateKey}; + #[derive(Clone)] #[allow(unused, non_camel_case_types)] pub enum EncString { @@ -304,8 +304,24 @@ impl EncString { EncString::Rsa2048_OaepSha1_HmacSha256_B64 { .. } => 6, } } +} + +fn invalid_len_error(expected: usize) -> impl Fn(Vec) -> EncStringParseError { + move |e: Vec<_>| EncStringParseError::InvalidLength { + expected, + got: e.len(), + } +} - pub fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result> { +impl LocateKey for EncString {} +impl KeyEncryptable for &[u8] { + fn encrypt_with_key(self, key: &SymmetricCryptoKey) -> Result { + super::encrypt_aes256_hmac(self, key.mac_key.ok_or(CryptoError::InvalidMac)?, key.key) + } +} + +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)?; @@ -317,22 +333,16 @@ impl EncString { } } -fn invalid_len_error(expected: usize) -> impl Fn(Vec) -> EncStringParseError { - move |e: Vec<_>| EncStringParseError::InvalidLength { - expected, - got: e.len(), - } -} - -impl Encryptable for String { - fn encrypt(self, enc: &EncryptionSettings, org_id: &Option) -> Result { - enc.encrypt(self.as_bytes(), org_id) +impl KeyEncryptable for String { + fn encrypt_with_key(self, key: &SymmetricCryptoKey) -> Result { + self.as_bytes().encrypt_with_key(key) } } -impl Decryptable for EncString { - fn decrypt(&self, enc: &EncryptionSettings, org_id: &Option) -> Result { - enc.decrypt(self, org_id) +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.into()) } } diff --git a/crates/bitwarden/src/crypto/encryptable.rs b/crates/bitwarden/src/crypto/encryptable.rs index bd987060f..10dbfaac6 100644 --- a/crates/bitwarden/src/crypto/encryptable.rs +++ b/crates/bitwarden/src/crypto/encryptable.rs @@ -2,7 +2,22 @@ use std::{collections::HashMap, hash::Hash}; use uuid::Uuid; -use crate::{client::encryption_settings::EncryptionSettings, error::Result}; +use crate::{ + client::encryption_settings::EncryptionSettings, + error::{Error, Result}, +}; + +use super::{KeyDecryptable, KeyEncryptable, SymmetricCryptoKey}; + +pub trait LocateKey { + fn locate_key<'a>( + &self, + enc: &'a EncryptionSettings, + org_id: &Option, + ) -> Option<&'a SymmetricCryptoKey> { + enc.get_key(org_id) + } +} pub trait Encryptable { fn encrypt(self, enc: &EncryptionSettings, org_id: &Option) -> Result; @@ -12,15 +27,17 @@ pub trait Decryptable { fn decrypt(&self, enc: &EncryptionSettings, org_id: &Option) -> Result; } -impl, Output> Encryptable> for Option { - fn encrypt(self, enc: &EncryptionSettings, org_id: &Option) -> Result> { - self.map(|e| e.encrypt(enc, org_id)).transpose() +impl + LocateKey, Output> Encryptable for T { + fn encrypt(self, enc: &EncryptionSettings, org_id: &Option) -> Result { + let key = self.locate_key(enc, org_id).ok_or(Error::VaultLocked)?; + self.encrypt_with_key(key) } } -impl, Output> Decryptable> for Option { - fn decrypt(&self, enc: &EncryptionSettings, org_id: &Option) -> Result> { - self.as_ref().map(|e| e.decrypt(enc, org_id)).transpose() +impl + LocateKey, Output> Decryptable for T { + fn decrypt(&self, enc: &EncryptionSettings, org_id: &Option) -> Result { + let key = self.locate_key(enc, org_id).ok_or(Error::VaultLocked)?; + self.decrypt_with_key(key) } } @@ -46,7 +63,7 @@ impl, Output, Id: Hash + Eq> Encryptable Result> { self.into_iter() .map(|(id, e)| Ok((id, e.encrypt(enc, org_id)?))) - .collect::>>() + .collect() } } @@ -60,18 +77,6 @@ impl, Output, Id: Hash + Eq + Copy> Decryptable Result> { self.iter() .map(|(id, e)| Ok((*id, e.decrypt(enc, org_id)?))) - .collect::>>() - } -} - -impl, Output> Encryptable for Box { - fn encrypt(self, enc: &EncryptionSettings, org_id: &Option) -> Result { - (*self).encrypt(enc, org_id) - } -} - -impl, Output> Decryptable for Box { - fn decrypt(&self, enc: &EncryptionSettings, org_id: &Option) -> Result { - (**self).decrypt(enc, org_id) + .collect() } } diff --git a/crates/bitwarden/src/crypto/key_encryptable.rs b/crates/bitwarden/src/crypto/key_encryptable.rs new file mode 100644 index 000000000..99c610bb2 --- /dev/null +++ b/crates/bitwarden/src/crypto/key_encryptable.rs @@ -0,0 +1,69 @@ +use std::{collections::HashMap, hash::Hash}; + +use crate::error::Result; + +use super::SymmetricCryptoKey; + +pub trait KeyEncryptable { + fn encrypt_with_key(self, key: &SymmetricCryptoKey) -> Result; +} + +pub trait KeyDecryptable { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result; +} + +impl, Output> KeyEncryptable> for Option { + fn encrypt_with_key(self, key: &SymmetricCryptoKey) -> Result> { + self.map(|e| e.encrypt_with_key(key)).transpose() + } +} + +impl, Output> KeyDecryptable> for Option { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result> { + self.as_ref().map(|e| e.decrypt_with_key(key)).transpose() + } +} + +impl, Output> KeyEncryptable for Box { + fn encrypt_with_key(self, key: &SymmetricCryptoKey) -> Result { + (*self).encrypt_with_key(key) + } +} + +impl, Output> KeyDecryptable for Box { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result { + (**self).decrypt_with_key(key) + } +} + +impl, Output> KeyEncryptable> for Vec { + fn encrypt_with_key(self, key: &SymmetricCryptoKey) -> Result> { + self.into_iter().map(|e| e.encrypt_with_key(key)).collect() + } +} + +impl, Output> KeyDecryptable> for Vec { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result> { + self.iter().map(|e| e.decrypt_with_key(key)).collect() + } +} + +impl, Output, Id: Hash + Eq> KeyEncryptable> + for HashMap +{ + fn encrypt_with_key(self, key: &SymmetricCryptoKey) -> Result> { + self.into_iter() + .map(|(id, e)| Ok((id, e.encrypt_with_key(key)?))) + .collect() + } +} + +impl, Output, Id: Hash + Eq + Copy> KeyDecryptable> + for HashMap +{ + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result> { + self.iter() + .map(|(id, e)| Ok((*id, e.decrypt_with_key(key)?))) + .collect() + } +} diff --git a/crates/bitwarden/src/crypto/master_key.rs b/crates/bitwarden/src/crypto/master_key.rs index f908d5299..064336edb 100644 --- a/crates/bitwarden/src/crypto/master_key.rs +++ b/crates/bitwarden/src/crypto/master_key.rs @@ -4,8 +4,8 @@ use rand::Rng; use sha2::Digest; use super::{ - encrypt_aes256, hkdf_expand, EncString, PbkdfSha256Hmac, SymmetricCryptoKey, UserKey, - PBKDF_SHA256_HMAC_OUT_SIZE, + encrypt_aes256, hkdf_expand, EncString, KeyDecryptable, PbkdfSha256Hmac, SymmetricCryptoKey, + UserKey, PBKDF_SHA256_HMAC_OUT_SIZE, }; use crate::{client::kdf::Kdf, error::Result, util::BASE64_ENGINE}; @@ -53,7 +53,7 @@ impl MasterKey { pub(crate) fn decrypt_user_key(&self, user_key: EncString) -> Result { let stretched_key = stretch_master_key(self)?; - let dec = user_key.decrypt_with_key(&stretched_key)?; + let dec: Vec = user_key.decrypt_with_key(&stretched_key)?; SymmetricCryptoKey::try_from(dec.as_slice()) } } diff --git a/crates/bitwarden/src/crypto/mod.rs b/crates/bitwarden/src/crypto/mod.rs index b35157981..d8a1f0557 100644 --- a/crates/bitwarden/src/crypto/mod.rs +++ b/crates/bitwarden/src/crypto/mod.rs @@ -29,7 +29,9 @@ use crate::error::{Error, Result}; mod enc_string; pub use enc_string::EncString; mod encryptable; -pub use encryptable::{Decryptable, Encryptable}; +pub use encryptable::{Decryptable, Encryptable, LocateKey}; +mod key_encryptable; +pub use key_encryptable::{KeyDecryptable, KeyEncryptable}; mod aes_ops; pub use aes_ops::{decrypt_aes256, decrypt_aes256_hmac, encrypt_aes256, encrypt_aes256_hmac}; mod symmetric_crypto_key; diff --git a/crates/bitwarden/src/mobile/vault/client_sends.rs b/crates/bitwarden/src/mobile/vault/client_sends.rs index 0adef3410..b1de05f44 100644 --- a/crates/bitwarden/src/mobile/vault/client_sends.rs +++ b/crates/bitwarden/src/mobile/vault/client_sends.rs @@ -2,8 +2,8 @@ use std::path::Path; use super::client_vault::ClientVault; use crate::{ - crypto::{Decryptable, EncString, Encryptable}, - error::Result, + crypto::{Decryptable, EncString, Encryptable, KeyDecryptable, KeyEncryptable}, + error::{Error, Result}, vault::{Send, SendListView, SendView}, Client, }; @@ -43,11 +43,11 @@ impl<'a> ClientSends<'a> { pub async fn decrypt_buffer(&self, send: Send, encrypted_buffer: &[u8]) -> Result> { let enc = self.client.get_encryption_settings()?; - let enc = Send::get_encryption(&send.key, enc, &None)?; + let key = enc.get_key(&None).ok_or(Error::VaultLocked)?; + let key = Send::get_key(&send.key, key)?; let buf = EncString::from_buffer(encrypted_buffer)?; - - enc.decrypt_bytes(&buf, &None) + buf.decrypt_with_key(&key) } pub async fn encrypt(&self, send_view: SendView) -> Result { @@ -71,10 +71,14 @@ impl<'a> ClientSends<'a> { } pub async fn encrypt_buffer(&self, send: Send, buffer: &[u8]) -> Result> { - let enc = self.client.get_encryption_settings()?; - let enc = Send::get_encryption(&send.key, enc, &None)?; - - let enc = enc.encrypt(buffer, &None)?; + let key = self + .client + .get_encryption_settings()? + .get_key(&None) + .ok_or(Error::VaultLocked)?; + let key = Send::get_key(&send.key, key)?; + + let enc = buffer.encrypt_with_key(&key)?; enc.to_buffer() } } diff --git a/crates/bitwarden/src/vault/cipher/attachment.rs b/crates/bitwarden/src/vault/cipher/attachment.rs index 143e2a4f9..101c8f4bc 100644 --- a/crates/bitwarden/src/vault/cipher/attachment.rs +++ b/crates/bitwarden/src/vault/cipher/attachment.rs @@ -1,10 +1,8 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use uuid::Uuid; use crate::{ - client::encryption_settings::EncryptionSettings, - crypto::{Decryptable, EncString, Encryptable}, + crypto::{EncString, KeyDecryptable, KeyEncryptable, SymmetricCryptoKey}, error::Result, }; @@ -33,28 +31,28 @@ pub struct AttachmentView { pub key: Option, } -impl Encryptable for AttachmentView { - fn encrypt(self, enc: &EncryptionSettings, org_id: &Option) -> Result { +impl KeyEncryptable for AttachmentView { + fn encrypt_with_key(self, key: &SymmetricCryptoKey) -> Result { Ok(Attachment { id: self.id, url: self.url, size: self.size, size_name: self.size_name, - file_name: self.file_name.encrypt(enc, org_id)?, - key: self.key.encrypt(enc, org_id)?, + file_name: self.file_name.encrypt_with_key(key)?, + key: self.key.encrypt_with_key(key)?, }) } } -impl Decryptable for Attachment { - fn decrypt(&self, enc: &EncryptionSettings, org_id: &Option) -> Result { +impl KeyDecryptable for Attachment { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result { Ok(AttachmentView { id: self.id.clone(), url: self.url.clone(), size: self.size.clone(), size_name: self.size_name.clone(), - file_name: self.file_name.decrypt(enc, org_id)?, - key: self.key.decrypt(enc, org_id)?, + file_name: self.file_name.decrypt_with_key(key)?, + key: self.key.decrypt_with_key(key)?, }) } } diff --git a/crates/bitwarden/src/vault/cipher/card.rs b/crates/bitwarden/src/vault/cipher/card.rs index 9636ba83f..1545ad171 100644 --- a/crates/bitwarden/src/vault/cipher/card.rs +++ b/crates/bitwarden/src/vault/cipher/card.rs @@ -1,10 +1,8 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use uuid::Uuid; use crate::{ - client::encryption_settings::EncryptionSettings, - crypto::{Decryptable, EncString, Encryptable}, + crypto::{EncString, KeyDecryptable, KeyEncryptable, SymmetricCryptoKey}, error::Result, }; @@ -32,28 +30,28 @@ pub struct CardView { pub number: Option, } -impl Encryptable for CardView { - fn encrypt(self, enc: &EncryptionSettings, org_id: &Option) -> Result { +impl KeyEncryptable for CardView { + fn encrypt_with_key(self, key: &SymmetricCryptoKey) -> Result { Ok(Card { - cardholder_name: self.cardholder_name.encrypt(enc, org_id)?, - exp_month: self.exp_month.encrypt(enc, org_id)?, - exp_year: self.exp_year.encrypt(enc, org_id)?, - code: self.code.encrypt(enc, org_id)?, - brand: self.brand.encrypt(enc, org_id)?, - number: self.number.encrypt(enc, org_id)?, + cardholder_name: self.cardholder_name.encrypt_with_key(key)?, + exp_month: self.exp_month.encrypt_with_key(key)?, + exp_year: self.exp_year.encrypt_with_key(key)?, + code: self.code.encrypt_with_key(key)?, + brand: self.brand.encrypt_with_key(key)?, + number: self.number.encrypt_with_key(key)?, }) } } -impl Decryptable for Card { - fn decrypt(&self, enc: &EncryptionSettings, org_id: &Option) -> Result { +impl KeyDecryptable for Card { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result { Ok(CardView { - cardholder_name: self.cardholder_name.decrypt(enc, org_id)?, - exp_month: self.exp_month.decrypt(enc, org_id)?, - exp_year: self.exp_year.decrypt(enc, org_id)?, - code: self.code.decrypt(enc, org_id)?, - brand: self.brand.decrypt(enc, org_id)?, - number: self.number.decrypt(enc, org_id)?, + cardholder_name: self.cardholder_name.decrypt_with_key(key)?, + exp_month: self.exp_month.decrypt_with_key(key)?, + exp_year: self.exp_year.decrypt_with_key(key)?, + code: self.code.decrypt_with_key(key)?, + brand: self.brand.decrypt_with_key(key)?, + number: self.number.decrypt_with_key(key)?, }) } } diff --git a/crates/bitwarden/src/vault/cipher/cipher.rs b/crates/bitwarden/src/vault/cipher/cipher.rs index 9bf4bbd25..b01f17136 100644 --- a/crates/bitwarden/src/vault/cipher/cipher.rs +++ b/crates/bitwarden/src/vault/cipher/cipher.rs @@ -11,7 +11,7 @@ use super::{ }; use crate::{ client::encryption_settings::EncryptionSettings, - crypto::{Decryptable, EncString, Encryptable}, + crypto::{EncString, KeyDecryptable, KeyEncryptable, LocateKey, SymmetricCryptoKey}, error::Result, vault::password_history, }; @@ -129,30 +129,29 @@ pub struct CipherListView { pub revision_date: DateTime, } -impl Encryptable for CipherView { - fn encrypt(self, enc: &EncryptionSettings, _: &Option) -> Result { - let org_id = &self.organization_id; +impl KeyEncryptable for CipherView { + fn encrypt_with_key(self, key: &SymmetricCryptoKey) -> Result { Ok(Cipher { id: self.id, organization_id: self.organization_id, folder_id: self.folder_id, collection_ids: self.collection_ids, - name: self.name.encrypt(enc, org_id)?, - notes: self.notes.encrypt(enc, org_id)?, + name: self.name.encrypt_with_key(key)?, + notes: self.notes.encrypt_with_key(key)?, r#type: self.r#type, - login: self.login.encrypt(enc, org_id)?, - identity: self.identity.encrypt(enc, org_id)?, - card: self.card.encrypt(enc, org_id)?, - secure_note: self.secure_note.encrypt(enc, org_id)?, + login: self.login.encrypt_with_key(key)?, + identity: self.identity.encrypt_with_key(key)?, + card: self.card.encrypt_with_key(key)?, + secure_note: self.secure_note.encrypt_with_key(key)?, favorite: self.favorite, reprompt: self.reprompt, organization_use_totp: self.organization_use_totp, edit: self.edit, view_password: self.view_password, - local_data: self.local_data.encrypt(enc, org_id)?, - attachments: self.attachments.encrypt(enc, org_id)?, - fields: self.fields.encrypt(enc, org_id)?, - password_history: self.password_history.encrypt(enc, org_id)?, + local_data: self.local_data.encrypt_with_key(key)?, + attachments: self.attachments.encrypt_with_key(key)?, + fields: self.fields.encrypt_with_key(key)?, + password_history: self.password_history.encrypt_with_key(key)?, creation_date: self.creation_date, deleted_date: self.deleted_date, revision_date: self.revision_date, @@ -160,30 +159,29 @@ impl Encryptable for CipherView { } } -impl Decryptable for Cipher { - fn decrypt(&self, enc: &EncryptionSettings, _: &Option) -> Result { - let org_id = &self.organization_id; +impl KeyDecryptable for Cipher { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result { Ok(CipherView { id: self.id, organization_id: self.organization_id, folder_id: self.folder_id, collection_ids: self.collection_ids.clone(), - name: self.name.decrypt(enc, org_id)?, - notes: self.notes.decrypt(enc, org_id)?, + name: self.name.decrypt_with_key(key)?, + notes: self.notes.decrypt_with_key(key)?, r#type: self.r#type, - login: self.login.decrypt(enc, org_id)?, - identity: self.identity.decrypt(enc, org_id)?, - card: self.card.decrypt(enc, org_id)?, - secure_note: self.secure_note.decrypt(enc, org_id)?, + login: self.login.decrypt_with_key(key)?, + identity: self.identity.decrypt_with_key(key)?, + card: self.card.decrypt_with_key(key)?, + secure_note: self.secure_note.decrypt_with_key(key)?, favorite: self.favorite, reprompt: self.reprompt, organization_use_totp: self.organization_use_totp, edit: self.edit, view_password: self.view_password, - local_data: self.local_data.decrypt(enc, org_id)?, - attachments: self.attachments.decrypt(enc, org_id)?, - fields: self.fields.decrypt(enc, org_id)?, - password_history: self.password_history.decrypt(enc, org_id)?, + local_data: self.local_data.decrypt_with_key(key)?, + attachments: self.attachments.decrypt_with_key(key)?, + fields: self.fields.decrypt_with_key(key)?, + password_history: self.password_history.decrypt_with_key(key)?, creation_date: self.creation_date, deleted_date: self.deleted_date, revision_date: self.revision_date, @@ -192,17 +190,13 @@ impl Decryptable for Cipher { } impl Cipher { - fn get_decrypted_subtitle( - &self, - enc: &EncryptionSettings, - org_id: &Option, - ) -> Result { + fn get_decrypted_subtitle(&self, key: &SymmetricCryptoKey) -> Result { Ok(match self.r#type { CipherType::Login => { let Some(login) = &self.login else { return Ok(String::new()); }; - login.username.decrypt(enc, org_id)?.unwrap_or_default() + login.username.decrypt_with_key(key)?.unwrap_or_default() } CipherType::SecureNote => String::new(), CipherType::Card => { @@ -212,11 +206,12 @@ impl Cipher { let mut sub_title = String::new(); if let Some(brand) = &card.brand { - sub_title.push_str(&brand.decrypt(enc, org_id)?); + let brand: String = brand.decrypt_with_key(key)?; + sub_title.push_str(&brand); } if let Some(number) = &card.number { - let number = number.decrypt(enc, org_id)?; + let number: String = number.decrypt_with_key(key)?; let number_len = number.len(); if number_len > 4 { if !sub_title.is_empty() { @@ -242,14 +237,16 @@ impl Cipher { let mut sub_title = String::new(); if let Some(first_name) = &identity.first_name { - sub_title.push_str(&first_name.decrypt(enc, org_id)?); + let first_name: String = first_name.decrypt_with_key(key)?; + sub_title.push_str(&first_name); } if let Some(last_name) = &identity.last_name { if !sub_title.is_empty() { sub_title.push(' '); } - sub_title.push_str(&last_name.decrypt(enc, org_id)?); + let last_name: String = last_name.decrypt_with_key(key)?; + sub_title.push_str(&last_name); } sub_title @@ -258,16 +255,15 @@ impl Cipher { } } -impl Decryptable for Cipher { - fn decrypt(&self, enc: &EncryptionSettings, _: &Option) -> Result { - let org_id = &self.organization_id; +impl KeyDecryptable for Cipher { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result { Ok(CipherListView { id: self.id, organization_id: self.organization_id, folder_id: self.folder_id, collection_ids: self.collection_ids.clone(), - name: self.name.decrypt(enc, org_id)?, - sub_title: self.get_decrypted_subtitle(enc, org_id)?, + name: self.name.decrypt_with_key(key)?, + sub_title: self.get_decrypted_subtitle(key)?, r#type: self.r#type, favorite: self.favorite, reprompt: self.reprompt, @@ -284,3 +280,22 @@ impl Decryptable for Cipher { }) } } + +impl LocateKey for Cipher { + fn locate_key<'a>( + &self, + enc: &'a EncryptionSettings, + _: &Option, + ) -> Option<&'a SymmetricCryptoKey> { + enc.get_key(&self.organization_id) + } +} +impl LocateKey for CipherView { + fn locate_key<'a>( + &self, + enc: &'a EncryptionSettings, + _: &Option, + ) -> Option<&'a SymmetricCryptoKey> { + enc.get_key(&self.organization_id) + } +} diff --git a/crates/bitwarden/src/vault/cipher/field.rs b/crates/bitwarden/src/vault/cipher/field.rs index 9fa05257a..13f7dc9bb 100644 --- a/crates/bitwarden/src/vault/cipher/field.rs +++ b/crates/bitwarden/src/vault/cipher/field.rs @@ -1,12 +1,10 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; -use uuid::Uuid; use super::linked_id::LinkedIdType; use crate::{ - client::encryption_settings::EncryptionSettings, - crypto::{Decryptable, EncString, Encryptable}, + crypto::{EncString, KeyDecryptable, KeyEncryptable, SymmetricCryptoKey}, error::Result, }; @@ -42,22 +40,22 @@ pub struct FieldView { linked_id: Option, } -impl Encryptable for FieldView { - fn encrypt(self, enc: &EncryptionSettings, org_id: &Option) -> Result { +impl KeyEncryptable for FieldView { + fn encrypt_with_key(self, key: &SymmetricCryptoKey) -> Result { Ok(Field { - name: self.name.encrypt(enc, org_id)?, - value: self.value.encrypt(enc, org_id)?, + name: self.name.encrypt_with_key(key)?, + value: self.value.encrypt_with_key(key)?, r#type: self.r#type, linked_id: self.linked_id, }) } } -impl Decryptable for Field { - fn decrypt(&self, enc: &EncryptionSettings, org_id: &Option) -> Result { +impl KeyDecryptable for Field { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result { Ok(FieldView { - name: self.name.decrypt(enc, org_id)?, - value: self.value.decrypt(enc, org_id)?, + name: self.name.decrypt_with_key(key)?, + value: self.value.decrypt_with_key(key)?, r#type: self.r#type, linked_id: self.linked_id, }) diff --git a/crates/bitwarden/src/vault/cipher/identity.rs b/crates/bitwarden/src/vault/cipher/identity.rs index aace84152..d40991866 100644 --- a/crates/bitwarden/src/vault/cipher/identity.rs +++ b/crates/bitwarden/src/vault/cipher/identity.rs @@ -1,10 +1,8 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use uuid::Uuid; use crate::{ - client::encryption_settings::EncryptionSettings, - crypto::{Decryptable, EncString, Encryptable}, + crypto::{EncString, KeyDecryptable, KeyEncryptable, SymmetricCryptoKey}, error::Result, }; @@ -56,52 +54,52 @@ pub struct IdentityView { pub license_number: Option, } -impl Encryptable for IdentityView { - fn encrypt(self, enc: &EncryptionSettings, org_id: &Option) -> Result { +impl KeyEncryptable for IdentityView { + fn encrypt_with_key(self, key: &SymmetricCryptoKey) -> Result { Ok(Identity { - title: self.title.encrypt(enc, org_id)?, - first_name: self.first_name.encrypt(enc, org_id)?, - middle_name: self.middle_name.encrypt(enc, org_id)?, - last_name: self.last_name.encrypt(enc, org_id)?, - address1: self.address1.encrypt(enc, org_id)?, - address2: self.address2.encrypt(enc, org_id)?, - address3: self.address3.encrypt(enc, org_id)?, - city: self.city.encrypt(enc, org_id)?, - state: self.state.encrypt(enc, org_id)?, - postal_code: self.postal_code.encrypt(enc, org_id)?, - country: self.country.encrypt(enc, org_id)?, - company: self.company.encrypt(enc, org_id)?, - email: self.email.encrypt(enc, org_id)?, - phone: self.phone.encrypt(enc, org_id)?, - ssn: self.ssn.encrypt(enc, org_id)?, - username: self.username.encrypt(enc, org_id)?, - passport_number: self.passport_number.encrypt(enc, org_id)?, - license_number: self.license_number.encrypt(enc, org_id)?, + title: self.title.encrypt_with_key(key)?, + first_name: self.first_name.encrypt_with_key(key)?, + middle_name: self.middle_name.encrypt_with_key(key)?, + last_name: self.last_name.encrypt_with_key(key)?, + address1: self.address1.encrypt_with_key(key)?, + address2: self.address2.encrypt_with_key(key)?, + address3: self.address3.encrypt_with_key(key)?, + city: self.city.encrypt_with_key(key)?, + state: self.state.encrypt_with_key(key)?, + postal_code: self.postal_code.encrypt_with_key(key)?, + country: self.country.encrypt_with_key(key)?, + company: self.company.encrypt_with_key(key)?, + email: self.email.encrypt_with_key(key)?, + phone: self.phone.encrypt_with_key(key)?, + ssn: self.ssn.encrypt_with_key(key)?, + username: self.username.encrypt_with_key(key)?, + passport_number: self.passport_number.encrypt_with_key(key)?, + license_number: self.license_number.encrypt_with_key(key)?, }) } } -impl Decryptable for Identity { - fn decrypt(&self, enc: &EncryptionSettings, org_id: &Option) -> Result { +impl KeyDecryptable for Identity { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result { Ok(IdentityView { - title: self.title.decrypt(enc, org_id)?, - first_name: self.first_name.decrypt(enc, org_id)?, - middle_name: self.middle_name.decrypt(enc, org_id)?, - last_name: self.last_name.decrypt(enc, org_id)?, - address1: self.address1.decrypt(enc, org_id)?, - address2: self.address2.decrypt(enc, org_id)?, - address3: self.address3.decrypt(enc, org_id)?, - city: self.city.decrypt(enc, org_id)?, - state: self.state.decrypt(enc, org_id)?, - postal_code: self.postal_code.decrypt(enc, org_id)?, - country: self.country.decrypt(enc, org_id)?, - company: self.company.decrypt(enc, org_id)?, - email: self.email.decrypt(enc, org_id)?, - phone: self.phone.decrypt(enc, org_id)?, - ssn: self.ssn.decrypt(enc, org_id)?, - username: self.username.decrypt(enc, org_id)?, - passport_number: self.passport_number.decrypt(enc, org_id)?, - license_number: self.license_number.decrypt(enc, org_id)?, + title: self.title.decrypt_with_key(key)?, + first_name: self.first_name.decrypt_with_key(key)?, + middle_name: self.middle_name.decrypt_with_key(key)?, + last_name: self.last_name.decrypt_with_key(key)?, + address1: self.address1.decrypt_with_key(key)?, + address2: self.address2.decrypt_with_key(key)?, + address3: self.address3.decrypt_with_key(key)?, + city: self.city.decrypt_with_key(key)?, + state: self.state.decrypt_with_key(key)?, + postal_code: self.postal_code.decrypt_with_key(key)?, + country: self.country.decrypt_with_key(key)?, + company: self.company.decrypt_with_key(key)?, + email: self.email.decrypt_with_key(key)?, + phone: self.phone.decrypt_with_key(key)?, + ssn: self.ssn.decrypt_with_key(key)?, + username: self.username.decrypt_with_key(key)?, + passport_number: self.passport_number.decrypt_with_key(key)?, + license_number: self.license_number.decrypt_with_key(key)?, }) } } diff --git a/crates/bitwarden/src/vault/cipher/local_data.rs b/crates/bitwarden/src/vault/cipher/local_data.rs index 1811ffa8b..8d5fe8694 100644 --- a/crates/bitwarden/src/vault/cipher/local_data.rs +++ b/crates/bitwarden/src/vault/cipher/local_data.rs @@ -1,10 +1,8 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use uuid::Uuid; use crate::{ - client::encryption_settings::EncryptionSettings, - crypto::{Decryptable, Encryptable}, + crypto::{KeyDecryptable, KeyEncryptable, SymmetricCryptoKey}, error::Result, }; @@ -24,8 +22,8 @@ pub struct LocalDataView { last_launched: Option, } -impl Encryptable for LocalDataView { - fn encrypt(self, _enc: &EncryptionSettings, _org_id: &Option) -> Result { +impl KeyEncryptable for LocalDataView { + fn encrypt_with_key(self, _key: &SymmetricCryptoKey) -> Result { Ok(LocalData { last_used_date: self.last_used_date, last_launched: self.last_launched, @@ -33,8 +31,8 @@ impl Encryptable for LocalDataView { } } -impl Decryptable for LocalData { - fn decrypt(&self, _enc: &EncryptionSettings, _org_id: &Option) -> Result { +impl KeyDecryptable for LocalData { + fn decrypt_with_key(&self, _key: &SymmetricCryptoKey) -> Result { Ok(LocalDataView { last_used_date: self.last_used_date, last_launched: self.last_launched, diff --git a/crates/bitwarden/src/vault/cipher/login.rs b/crates/bitwarden/src/vault/cipher/login.rs index 941aed221..7a8e18411 100644 --- a/crates/bitwarden/src/vault/cipher/login.rs +++ b/crates/bitwarden/src/vault/cipher/login.rs @@ -2,11 +2,9 @@ use chrono::{DateTime, Utc}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; -use uuid::Uuid; use crate::{ - client::encryption_settings::EncryptionSettings, - crypto::{Decryptable, EncString, Encryptable}, + crypto::{EncString, KeyDecryptable, KeyEncryptable, SymmetricCryptoKey}, error::Result, }; @@ -65,45 +63,45 @@ pub struct LoginView { pub autofill_on_page_load: Option, } -impl Encryptable for LoginUriView { - fn encrypt(self, enc: &EncryptionSettings, org_id: &Option) -> Result { +impl KeyEncryptable for LoginUriView { + fn encrypt_with_key(self, key: &SymmetricCryptoKey) -> Result { Ok(LoginUri { - uri: self.uri.encrypt(enc, org_id)?, + uri: self.uri.encrypt_with_key(key)?, r#match: self.r#match, }) } } -impl Encryptable for LoginView { - fn encrypt(self, enc: &EncryptionSettings, org_id: &Option) -> Result { +impl KeyEncryptable for LoginView { + fn encrypt_with_key(self, key: &SymmetricCryptoKey) -> Result { Ok(Login { - username: self.username.encrypt(enc, org_id)?, - password: self.password.encrypt(enc, org_id)?, + username: self.username.encrypt_with_key(key)?, + password: self.password.encrypt_with_key(key)?, password_revision_date: self.password_revision_date, - uris: self.uris.encrypt(enc, org_id)?, - totp: self.totp.encrypt(enc, org_id)?, + uris: self.uris.encrypt_with_key(key)?, + totp: self.totp.encrypt_with_key(key)?, autofill_on_page_load: self.autofill_on_page_load, }) } } -impl Decryptable for LoginUri { - fn decrypt(&self, enc: &EncryptionSettings, org_id: &Option) -> Result { +impl KeyDecryptable for LoginUri { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result { Ok(LoginUriView { - uri: self.uri.decrypt(enc, org_id)?, + uri: self.uri.decrypt_with_key(key)?, r#match: self.r#match, }) } } -impl Decryptable for Login { - fn decrypt(&self, enc: &EncryptionSettings, org_id: &Option) -> Result { +impl KeyDecryptable for Login { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result { Ok(LoginView { - username: self.username.decrypt(enc, org_id)?, - password: self.password.decrypt(enc, org_id)?, + username: self.username.decrypt_with_key(key)?, + password: self.password.decrypt_with_key(key)?, password_revision_date: self.password_revision_date, - uris: self.uris.decrypt(enc, org_id)?, - totp: self.totp.decrypt(enc, org_id)?, + uris: self.uris.decrypt_with_key(key)?, + totp: self.totp.decrypt_with_key(key)?, autofill_on_page_load: self.autofill_on_page_load, }) } diff --git a/crates/bitwarden/src/vault/cipher/secure_note.rs b/crates/bitwarden/src/vault/cipher/secure_note.rs index 422a55da1..0c7b4c799 100644 --- a/crates/bitwarden/src/vault/cipher/secure_note.rs +++ b/crates/bitwarden/src/vault/cipher/secure_note.rs @@ -1,11 +1,9 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; -use uuid::Uuid; use crate::{ - client::encryption_settings::EncryptionSettings, - crypto::{Decryptable, Encryptable}, + crypto::{KeyDecryptable, KeyEncryptable, SymmetricCryptoKey}, error::Result, }; @@ -30,16 +28,16 @@ pub struct SecureNoteView { r#type: SecureNoteType, } -impl Encryptable for SecureNoteView { - fn encrypt(self, _enc: &EncryptionSettings, _org_id: &Option) -> Result { +impl KeyEncryptable for SecureNoteView { + fn encrypt_with_key(self, _key: &SymmetricCryptoKey) -> Result { Ok(SecureNote { r#type: self.r#type, }) } } -impl Decryptable for SecureNote { - fn decrypt(&self, _enc: &EncryptionSettings, _org_id: &Option) -> Result { +impl KeyDecryptable for SecureNote { + fn decrypt_with_key(&self, _key: &SymmetricCryptoKey) -> Result { Ok(SecureNoteView { r#type: self.r#type, }) diff --git a/crates/bitwarden/src/vault/collection.rs b/crates/bitwarden/src/vault/collection.rs index 38863a946..58492ef17 100644 --- a/crates/bitwarden/src/vault/collection.rs +++ b/crates/bitwarden/src/vault/collection.rs @@ -4,7 +4,7 @@ use uuid::Uuid; use crate::{ client::encryption_settings::EncryptionSettings, - crypto::{Decryptable, EncString}, + crypto::{EncString, KeyDecryptable, LocateKey, SymmetricCryptoKey}, error::Result, }; @@ -36,15 +36,22 @@ pub struct CollectionView { read_only: bool, } -impl Decryptable for Collection { - fn decrypt(&self, enc: &EncryptionSettings, _: &Option) -> Result { - let org_id = Some(self.organization_id); - +impl LocateKey for Collection { + fn locate_key<'a>( + &self, + enc: &'a EncryptionSettings, + _: &Option, + ) -> Option<&'a SymmetricCryptoKey> { + enc.get_key(&Some(self.organization_id)) + } +} +impl KeyDecryptable for Collection { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result { Ok(CollectionView { id: self.id, organization_id: self.organization_id, - name: self.name.decrypt(enc, &org_id)?, + name: self.name.decrypt_with_key(key)?, external_id: self.external_id.clone(), hide_passwords: self.hide_passwords, diff --git a/crates/bitwarden/src/vault/folder.rs b/crates/bitwarden/src/vault/folder.rs index 97d861310..f9ae06055 100644 --- a/crates/bitwarden/src/vault/folder.rs +++ b/crates/bitwarden/src/vault/folder.rs @@ -4,8 +4,7 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; use crate::{ - client::encryption_settings::EncryptionSettings, - crypto::{Decryptable, EncString, Encryptable}, + crypto::{EncString, KeyDecryptable, KeyEncryptable, LocateKey, SymmetricCryptoKey}, error::Result, }; @@ -27,21 +26,23 @@ pub struct FolderView { revision_date: DateTime, } -impl Encryptable for FolderView { - fn encrypt(self, enc: &EncryptionSettings, _org: &Option) -> Result { +impl LocateKey for FolderView {} +impl KeyEncryptable for FolderView { + fn encrypt_with_key(self, key: &SymmetricCryptoKey) -> Result { Ok(Folder { id: self.id, - name: self.name.encrypt(enc, &None)?, + name: self.name.encrypt_with_key(key)?, revision_date: self.revision_date, }) } } -impl Decryptable for Folder { - fn decrypt(&self, enc: &EncryptionSettings, _org: &Option) -> Result { +impl LocateKey for Folder {} +impl KeyDecryptable for Folder { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result { Ok(FolderView { id: self.id, - name: self.name.decrypt(enc, &None)?, + name: self.name.decrypt_with_key(key)?, revision_date: self.revision_date, }) } diff --git a/crates/bitwarden/src/vault/password_history.rs b/crates/bitwarden/src/vault/password_history.rs index 8566c9870..da6a4b19e 100644 --- a/crates/bitwarden/src/vault/password_history.rs +++ b/crates/bitwarden/src/vault/password_history.rs @@ -1,11 +1,9 @@ use chrono::{DateTime, Utc}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use uuid::Uuid; use crate::{ - client::encryption_settings::EncryptionSettings, - crypto::{Decryptable, EncString, Encryptable}, + crypto::{EncString, KeyDecryptable, KeyEncryptable, LocateKey, SymmetricCryptoKey}, error::Result, }; @@ -25,23 +23,21 @@ pub struct PasswordHistoryView { last_used_date: DateTime, } -impl Encryptable for PasswordHistoryView { - fn encrypt(self, enc: &EncryptionSettings, org_id: &Option) -> Result { +impl LocateKey for PasswordHistoryView {} +impl KeyEncryptable for PasswordHistoryView { + fn encrypt_with_key(self, key: &SymmetricCryptoKey) -> Result { Ok(PasswordHistory { - password: self.password.encrypt(enc, org_id)?, + password: self.password.encrypt_with_key(key)?, last_used_date: self.last_used_date, }) } } -impl Decryptable for PasswordHistory { - fn decrypt( - &self, - enc: &EncryptionSettings, - org_id: &Option, - ) -> Result { +impl LocateKey for PasswordHistory {} +impl KeyDecryptable for PasswordHistory { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result { Ok(PasswordHistoryView { - password: self.password.decrypt(enc, org_id)?, + password: self.password.decrypt_with_key(key)?, last_used_date: self.last_used_date, }) } diff --git a/crates/bitwarden/src/vault/send.rs b/crates/bitwarden/src/vault/send.rs index 124b9dc2f..5c463a0cf 100644 --- a/crates/bitwarden/src/vault/send.rs +++ b/crates/bitwarden/src/vault/send.rs @@ -5,8 +5,10 @@ use serde_repr::{Deserialize_repr, Serialize_repr}; use uuid::Uuid; use crate::{ - client::encryption_settings::EncryptionSettings, - crypto::{derive_shareable_key, Decryptable, EncString, Encryptable, SymmetricCryptoKey}, + crypto::{ + derive_shareable_key, EncString, KeyDecryptable, KeyEncryptable, LocateKey, + SymmetricCryptoKey, + }, error::Result, }; @@ -126,86 +128,75 @@ pub struct SendListView { } impl Send { - fn get_key( - key: &EncString, - enc: &EncryptionSettings, - org_id: &Option, + pub(crate) fn get_key( + send_key: &EncString, + enc_key: &SymmetricCryptoKey, ) -> Result { - let key: Vec = enc.decrypt_bytes(key, org_id)?; + let key: Vec = send_key.decrypt_with_key(enc_key)?; let key = derive_shareable_key(key.try_into().unwrap(), "send", Some("send")); Ok(key) } - - pub(crate) fn get_encryption( - key: &EncString, - enc: &EncryptionSettings, - org_id: &Option, - ) -> Result { - let key = Send::get_key(key, enc, org_id)?; - Ok(EncryptionSettings::new_single_key(key)) - } } -impl Decryptable for SendText { - fn decrypt(&self, enc: &EncryptionSettings, org_id: &Option) -> Result { +impl KeyDecryptable for SendText { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result { Ok(SendTextView { - text: self.text.decrypt(enc, org_id)?, + text: self.text.decrypt_with_key(key)?, hidden: self.hidden, }) } } -impl Encryptable for SendTextView { - fn encrypt(self, enc: &EncryptionSettings, org_id: &Option) -> Result { +impl KeyEncryptable for SendTextView { + fn encrypt_with_key(self, key: &SymmetricCryptoKey) -> Result { Ok(SendText { - text: self.text.encrypt(enc, org_id)?, + text: self.text.encrypt_with_key(key)?, hidden: self.hidden, }) } } -impl Decryptable for SendFile { - fn decrypt(&self, enc: &EncryptionSettings, org_id: &Option) -> Result { +impl KeyDecryptable for SendFile { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result { Ok(SendFileView { id: self.id.clone(), - file_name: self.file_name.decrypt(enc, org_id)?, + file_name: self.file_name.decrypt_with_key(key)?, size: self.size.clone(), size_name: self.size_name.clone(), }) } } -impl Encryptable for SendFileView { - fn encrypt(self, enc: &EncryptionSettings, org_id: &Option) -> Result { +impl KeyEncryptable for SendFileView { + fn encrypt_with_key(self, key: &SymmetricCryptoKey) -> Result { Ok(SendFile { id: self.id.clone(), - file_name: self.file_name.encrypt(enc, org_id)?, + file_name: self.file_name.encrypt_with_key(key)?, size: self.size.clone(), size_name: self.size_name.clone(), }) } } -impl Decryptable for Send { - fn decrypt(&self, enc: &EncryptionSettings, org_id: &Option) -> Result { +impl LocateKey for Send {} +impl KeyDecryptable for Send { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result { // For sends, we first decrypt the send key with the user key, and stretch it to it's full size - let enc_owned = Send::get_encryption(&self.key, enc, org_id)?; - - // For the rest of the fields, we ignore the provided EncryptionSettings and use a new one with the stretched key - let enc = &enc_owned; + // For the rest of the fields, we ignore the provided SymmetricCryptoKey and the stretched key + let key = Send::get_key(&self.key, key)?; Ok(SendView { id: self.id, access_id: self.access_id.clone(), - name: self.name.decrypt(enc, org_id)?, - notes: self.notes.decrypt(enc, org_id)?, + name: self.name.decrypt_with_key(&key)?, + notes: self.notes.decrypt_with_key(&key)?, key: self.key.clone(), password: self.password.clone(), r#type: self.r#type, - file: self.file.decrypt(enc, org_id)?, - text: self.text.decrypt(enc, org_id)?, + file: self.file.decrypt_with_key(&key)?, + text: self.text.decrypt_with_key(&key)?, max_access_count: self.max_access_count, access_count: self.access_count, @@ -219,19 +210,17 @@ impl Decryptable for Send { } } -impl Decryptable for Send { - fn decrypt(&self, enc: &EncryptionSettings, org_id: &Option) -> Result { +impl KeyDecryptable for Send { + fn decrypt_with_key(&self, key: &SymmetricCryptoKey) -> Result { // For sends, we first decrypt the send key with the user key, and stretch it to it's full size - let enc_owned = Send::get_encryption(&self.key, enc, org_id)?; - - // For the rest of the fields, we ignore the provided EncryptionSettings and use a new one with the stretched key - let enc = &enc_owned; + // For the rest of the fields, we ignore the provided SymmetricCryptoKey and the stretched key + let key = Send::get_key(&self.key, key)?; Ok(SendListView { id: self.id, access_id: self.access_id.clone(), - name: self.name.decrypt(enc, org_id)?, + name: self.name.decrypt_with_key(&key)?, r#type: self.r#type, disabled: self.disabled, @@ -243,27 +232,25 @@ impl Decryptable for Send { } } -impl Encryptable for SendView { - fn encrypt(self, enc: &EncryptionSettings, org_id: &Option) -> Result { +impl LocateKey for SendView {} +impl KeyEncryptable for SendView { + fn encrypt_with_key(self, key: &SymmetricCryptoKey) -> Result { // For sends, we first decrypt the send key with the user key, and stretch it to it's full size - let key = Send::get_key(&self.key, enc, org_id)?; - let enc_owned = EncryptionSettings::new_single_key(key); - - // For the rest of the fields, we ignore the provided EncryptionSettings and use a new one with the stretched key - let enc = &enc_owned; + // For the rest of the fields, we ignore the provided SymmetricCryptoKey and the stretched key + let key = Send::get_key(&self.key, key)?; Ok(Send { id: self.id, access_id: self.access_id, - name: self.name.encrypt(enc, org_id)?, - notes: self.notes.encrypt(enc, org_id)?, + name: self.name.encrypt_with_key(&key)?, + notes: self.notes.encrypt_with_key(&key)?, key: self.key.clone(), password: self.password.clone(), r#type: self.r#type, - file: self.file.encrypt(enc, org_id)?, - text: self.text.encrypt(enc, org_id)?, + file: self.file.encrypt_with_key(&key)?, + text: self.text.encrypt_with_key(&key)?, max_access_count: self.max_access_count, access_count: self.access_count, @@ -298,6 +285,8 @@ mod tests { "2.kmLY8NJVuiKBFJtNd/ZFpA==|qOodlRXER+9ogCe3yOibRHmUcSNvjSKhdDuztLlucs10jLiNoVVVAc+9KfNErLSpx5wmUF1hBOJM8zwVPjgQTrmnNf/wuDpwiaCxNYb/0v4FygPy7ccAHK94xP1lfqq7U9+tv+/yiZSwgcT+xF0wFpoxQeNdNRFzPTuD9o4134n8bzacD9DV/WjcrXfRjbBCzzuUGj1e78+A7BWN7/5IWLz87KWk8G7O/W4+8PtEzlwkru6Wd1xO19GYU18oArCWCNoegSmcGn7w7NDEXlwD403oY8Oa7ylnbqGE28PVJx+HLPNIdSC6YKXeIOMnVs7Mctd/wXC93zGxAWD6ooTCzHSPVV50zKJmWIG2cVVUS7j35H3rGDtUHLI+ASXMEux9REZB8CdVOZMzp2wYeiOpggebJy6MKOZqPT1R3X0fqF2dHtRFPXrNsVr1Qt6bS9qTyO4ag1/BCvXF3P1uJEsI812BFAne3cYHy5bIOxuozPfipJrTb5WH35bxhElqwT3y/o/6JWOGg3HLDun31YmiZ2HScAsUAcEkA4hhoTNnqy4O2s3yVbCcR7jF7NLsbQc0MDTbnjxTdI4VnqUIn8s2c9hIJy/j80pmO9Bjxp+LQ9a2hUkfHgFhgHxZUVaeGVth8zG2kkgGdrp5VHhxMVFfvB26Ka6q6qE/UcS2lONSv+4T8niVRJz57qwctj8MNOkA3PTEfe/DP/LKMefke31YfT0xogHsLhDkx+mS8FCc01HReTjKLktk/Jh9mXwC5oKwueWWwlxI935ecn+3I2kAuOfMsgPLkoEBlwgiREC1pM7VVX1x8WmzIQVQTHd4iwnX96QewYckGRfNYWz/zwvWnjWlfcg8kRSe+68EHOGeRtC5r27fWLqRc0HNcjwpgHkI/b6czerCe8+07TWql4keJxJxhBYj3iOH7r9ZS8ck51XnOb8tGL1isimAJXodYGzakwktqHAD7MZhS+P02O+6jrg7d+yPC2ZCuS/3TOplYOCHQIhnZtR87PXTUwr83zfOwAwCyv6KP84JUQ45+DItrXLap7nOVZKQ5QxYIlbThAO6eima6Zu5XHfqGPMNWv0bLf5+vAjIa5np5DJrSwz9no/hj6CUh0iyI+SJq4RGI60lKtypMvF6MR3nHLEHOycRUQbZIyTHWl4QQLdHzuwN9lv10ouTEvNr6sFflAX2yb6w3hlCo7oBytH3rJekjb3IIOzBpeTPIejxzVlh0N9OT5MZdh4sNKYHUoWJ8mnfjdM+L4j5Q2Kgk/XiGDgEebkUxiEOQUdVpePF5uSCE+TPav/9FIRGXGiFn6NJMaU7aBsDTFBLloffFLYDpd8/bTwoSvifkj7buwLYM+h/qcnfdy5FWau1cKav+Blq/ZC0qBpo658RTC8ZtseAFDgXoQZuksM10hpP9bzD04Bx30xTGX81QbaSTNwSEEVrOtIhbDrj9OI43KH4O6zLzK+t30QxAv5zjk10RZ4+5SAdYndIlld9Y62opCfPDzRy3ubdve4ZEchpIKWTQvIxq3T5ogOhGaWBVYnkMtM2GVqvWV//46gET5SH/MdcwhACUcZ9kCpMnWH9CyyUwYvTT3UlNyV+DlS27LMPvaw7tx7qa+GfNCoCBd8S4esZpQYK/WReiS8=|pc7qpD42wxyXemdNPuwxbh8iIaryrBPu8f/DGwYdHTw=".parse().unwrap(), ).unwrap(); + let k = enc.get_key(&None).unwrap(); + // Create a send object, the only value we really care about here is the key let send = Send { id: "d7fb1e7f-9053-43c0-a02c-b0690098685a".parse().unwrap(), @@ -330,7 +319,7 @@ mod tests { }; // Get the send key - let send_key = Send::get_key(&send.key, &enc, &None).unwrap(); + let send_key = Send::get_key(&send.key, k).unwrap(); let send_key_b64 = send_key.to_base64(); assert_eq!(send_key_b64, "IR9ImHGm6rRuIjiN7csj94bcZR5WYTJj5GtNfx33zm6tJCHUl+QZlpNPba8g2yn70KnOHsAODLcR0um6E3MAlg=="); } From 8ece8a8306110244c27e3ab5cc91ed19c2990fa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garci=CC=81a?= Date: Thu, 19 Oct 2023 18:09:23 +0200 Subject: [PATCH 2/3] Fix internal import --- crates/bitwarden/src/client/encryption_settings.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bitwarden/src/client/encryption_settings.rs b/crates/bitwarden/src/client/encryption_settings.rs index 83a4f87ea..7b0104f15 100644 --- a/crates/bitwarden/src/client/encryption_settings.rs +++ b/crates/bitwarden/src/client/encryption_settings.rs @@ -4,12 +4,12 @@ use rsa::RsaPrivateKey; use uuid::Uuid; #[cfg(feature = "internal")] use { - crate::client::UserLoginMethod, + crate::{client::UserLoginMethod, crypto::KeyDecryptable}, rsa::{pkcs8::DecodePrivateKey, Oaep}, }; use crate::{ - crypto::{encrypt_aes256_hmac, EncString, KeyDecryptable, SymmetricCryptoKey}, + crypto::{encrypt_aes256_hmac, EncString, SymmetricCryptoKey}, error::{CryptoError, Result}, }; From bb358a38fb203e307571c1aa50d9562b01b60562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garci=CC=81a?= Date: Mon, 30 Oct 2023 14:27:05 +0100 Subject: [PATCH 3/3] Move test to enc-string --- .../bitwarden/src/client/encryption_settings.rs | 17 ----------------- crates/bitwarden/src/crypto/enc_string.rs | 13 +++++++++++++ 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/crates/bitwarden/src/client/encryption_settings.rs b/crates/bitwarden/src/client/encryption_settings.rs index 7b0104f15..e6cf3e145 100644 --- a/crates/bitwarden/src/client/encryption_settings.rs +++ b/crates/bitwarden/src/client/encryption_settings.rs @@ -117,20 +117,3 @@ impl EncryptionSettings { Ok(dec) } } - -#[cfg(test)] -mod tests { - use super::SymmetricCryptoKey; - use crate::crypto::{KeyDecryptable, KeyEncryptable}; - - #[test] - fn test_encryption_settings() { - let key = SymmetricCryptoKey::generate("test"); - - let test_string = "encrypted_test_string".to_string(); - let cipher = test_string.clone().encrypt_with_key(&key).unwrap(); - - let decrypted_str: String = cipher.decrypt_with_key(&key).unwrap(); - assert_eq!(decrypted_str, test_string); - } -} diff --git a/crates/bitwarden/src/crypto/enc_string.rs b/crates/bitwarden/src/crypto/enc_string.rs index 4d71696db..976065e60 100644 --- a/crates/bitwarden/src/crypto/enc_string.rs +++ b/crates/bitwarden/src/crypto/enc_string.rs @@ -348,8 +348,21 @@ impl KeyDecryptable for EncString { #[cfg(test)] mod tests { + use crate::crypto::{KeyDecryptable, KeyEncryptable, SymmetricCryptoKey}; + use super::EncString; + #[test] + fn test_enc_string_roundtrip() { + let key = SymmetricCryptoKey::generate("test"); + + let test_string = "encrypted_test_string".to_string(); + let cipher = test_string.clone().encrypt_with_key(&key).unwrap(); + + let decrypted_str: String = cipher.decrypt_with_key(&key).unwrap(); + assert_eq!(decrypted_str, test_string); + } + #[test] fn test_enc_string_serialization() { #[derive(serde::Serialize, serde::Deserialize)]