From 37e4eaf9c66fdc2d54a88cbb4c5c25258b15ec1a Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Tue, 9 Jan 2024 11:17:51 +0100 Subject: [PATCH] Support generating a random send key if none is provided (#488) When creating a new send, we should generate a key for it. --- crates/bitwarden/src/crypto/mod.rs | 12 ++++ .../src/crypto/symmetric_crypto_key.rs | 5 +- crates/bitwarden/src/vault/send.rs | 60 +++++++++++++++++-- 3 files changed, 69 insertions(+), 8 deletions(-) diff --git a/crates/bitwarden/src/crypto/mod.rs b/crates/bitwarden/src/crypto/mod.rs index 84697e8a5..94db974d3 100644 --- a/crates/bitwarden/src/crypto/mod.rs +++ b/crates/bitwarden/src/crypto/mod.rs @@ -23,6 +23,10 @@ use aes::cipher::{generic_array::GenericArray, ArrayLength, Unsigned}; use hmac::digest::OutputSizeUser; +use rand::{ + distributions::{Distribution, Standard}, + Rng, +}; use crate::error::Result; @@ -73,3 +77,11 @@ fn hkdf_expand>(prk: &[u8], info: Option<&str>) -> Result() -> T +where + Standard: Distribution, +{ + rand::thread_rng().gen() +} diff --git a/crates/bitwarden/src/crypto/symmetric_crypto_key.rs b/crates/bitwarden/src/crypto/symmetric_crypto_key.rs index 5bce9e65d..741fe0559 100644 --- a/crates/bitwarden/src/crypto/symmetric_crypto_key.rs +++ b/crates/bitwarden/src/crypto/symmetric_crypto_key.rs @@ -4,7 +4,7 @@ use aes::cipher::{generic_array::GenericArray, typenum::U32}; use base64::Engine; use crate::{ - crypto::derive_shareable_key, + crypto::{derive_shareable_key, generate_random_bytes}, error::{CryptoError, Error}, util::BASE64_ENGINE, }; @@ -20,8 +20,7 @@ impl SymmetricCryptoKey { const MAC_LEN: usize = 32; pub fn generate(name: &str) -> Self { - use rand::Rng; - let secret: [u8; 16] = rand::thread_rng().gen(); + let secret: [u8; 16] = generate_random_bytes(); derive_shareable_key(secret, name, None) } diff --git a/crates/bitwarden/src/vault/send.rs b/crates/bitwarden/src/vault/send.rs index e0699ef9c..ce100db3e 100644 --- a/crates/bitwarden/src/vault/send.rs +++ b/crates/bitwarden/src/vault/send.rs @@ -8,8 +8,8 @@ use uuid::Uuid; use crate::{ crypto::{ - derive_shareable_key, EncString, KeyDecryptable, KeyEncryptable, LocateKey, - SymmetricCryptoKey, + derive_shareable_key, generate_random_bytes, EncString, KeyDecryptable, KeyEncryptable, + LocateKey, SymmetricCryptoKey, }, error::{CryptoError, Error, Result}, }; @@ -245,9 +245,19 @@ 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 // For the rest of the fields, we ignore the provided SymmetricCryptoKey and the stretched key - let k = URL_SAFE_NO_PAD - .decode(self.key.ok_or(CryptoError::MissingKey)?) - .map_err(|_| CryptoError::InvalidKey)?; + let k = match (self.key, self.id) { + // Existing send, decrypt key + (Some(k), _) => URL_SAFE_NO_PAD + .decode(k) + .map_err(|_| CryptoError::InvalidKey)?, + // New send, generate random key + (None, None) => { + let key: [u8; 16] = generate_random_bytes(); + key.to_vec() + } + // Existing send without key + _ => return Err(CryptoError::InvalidKey.into()), + }; let send_key = Send::derive_shareable_key(&k)?; Ok(Send { @@ -503,4 +513,44 @@ mod tests { .unwrap(); assert_eq!(v, view); } + + #[test] + pub fn test_encrypt_no_key() { + let enc = build_encryption_settings(); + let key = enc.get_key(&None).unwrap(); + + let view = SendView { + id: None, + access_id: Some("ct2APRQtJk-BLLDwAYqhRA".to_owned()), + name: "Test".to_string(), + notes: None, + key: None, + password: None, + r#type: SendType::Text, + file: None, + text: Some(SendTextView { + text: Some("This is a test".to_owned()), + hidden: false, + }), + max_access_count: None, + access_count: 0, + disabled: false, + hide_email: false, + revision_date: "2024-01-07T23:56:48.207363Z".parse().unwrap(), + deletion_date: "2024-01-14T23:56:48Z".parse().unwrap(), + expiration_date: None, + }; + + // Re-encrypt and decrypt again to ensure encrypt works + let v: SendView = view + .clone() + .encrypt_with_key(key) + .unwrap() + .decrypt_with_key(key) + .unwrap(); + + // Ignore key when comparing + let t = SendView { key: None, ..v }; + assert_eq!(t, view); + } }