Skip to content

Commit

Permalink
Support generating a random send key if none is provided (#488)
Browse files Browse the repository at this point in the history
When creating a new send, we should generate a key for it.
  • Loading branch information
Hinton authored Jan 9, 2024
1 parent 6796730 commit 37e4eaf
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 8 deletions.
12 changes: 12 additions & 0 deletions crates/bitwarden/src/crypto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -73,3 +77,11 @@ fn hkdf_expand<T: ArrayLength<u8>>(prk: &[u8], info: Option<&str>) -> Result<Gen

Ok(key)
}

/// Generate random bytes that are cryptographically secure
pub(crate) fn generate_random_bytes<T>() -> T
where
Standard: Distribution<T>,
{
rand::thread_rng().gen()
}
5 changes: 2 additions & 3 deletions crates/bitwarden/src/crypto/symmetric_crypto_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand All @@ -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)
}

Expand Down
60 changes: 55 additions & 5 deletions crates/bitwarden/src/vault/send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
};
Expand Down Expand Up @@ -245,9 +245,19 @@ impl KeyEncryptable<Send> for SendView {
fn encrypt_with_key(self, key: &SymmetricCryptoKey) -> Result<Send> {
// 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 {
Expand Down Expand Up @@ -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);
}
}

0 comments on commit 37e4eaf

Please sign in to comment.