diff --git a/crates/bitwarden-user-crypto-management/src/key_rotation/data.rs b/crates/bitwarden-user-crypto-management/src/key_rotation/data.rs index 290519cfb..9fa4cf204 100644 --- a/crates/bitwarden-user-crypto-management/src/key_rotation/data.rs +++ b/crates/bitwarden-user-crypto-management/src/key_rotation/data.rs @@ -153,11 +153,10 @@ fn reencrypt_ciphers( .collect::, DataReencryptionError>>() } -/// Decrypts a legacy cipher into a view that can be re-sealed as a blob under `new_key`. +/// Decrypts a legacy cipher into a view ready to be re-sealed as a blob under `new_key`. /// -/// If the cipher has a per-item key, it is re-wrapped under the new user key first so the cipher -/// key (and the data sealed against it) stay consistent under the new key. Otherwise the cipher is -/// decrypted under the current key and blob sealing will generate a fresh per-item key. +/// The returned view carries a per-item cipher key wrapped under `new_key`, with its sub-keys +/// (attachment keys, FIDO2 credentials) wrapped under that cipher key. fn decrypt_for_blob_upgrade( cipher: &bitwarden_vault::Cipher, current_key: SymmetricKeySlotId, @@ -173,9 +172,12 @@ fn decrypt_for_blob_upgrade( .decrypt(ctx, new_key) .map_err(|_| DataReencryptionError::Decryption) } else { - cipher + let mut view: CipherView = cipher .decrypt(ctx, current_key) - .map_err(|_| DataReencryptionError::Decryption) + .map_err(|_| DataReencryptionError::Decryption)?; + view.upgrade_to_cipher_key_encryption_with_external_key(ctx, current_key, new_key) + .map_err(|_| DataReencryptionError::Encryption)?; + Ok(view) } } @@ -202,10 +204,13 @@ fn reencrypt_sends( #[cfg(test)] mod tests { - use bitwarden_core::key_management::KeySlotIds; - use bitwarden_crypto::{CompositeEncryptable, Decryptable, KeyStore}; + use bitwarden_core::key_management::{KeySlotIds, SymmetricKeySlotId}; + use bitwarden_crypto::{CompositeEncryptable, Decryptable, KeyStore, PrimitiveEncryptable}; use bitwarden_send::SendView; - use bitwarden_vault::{Attachment, Cipher, CipherRepromptType, CipherType, EncryptMode}; + use bitwarden_vault::{ + Attachment, Cipher, CipherRepromptType, CipherType, CipherView, EncryptMode, + Fido2CredentialFullView, + }; use chrono::Utc; use super::check_for_old_attachments; @@ -351,8 +356,8 @@ mod tests { fn assert_decrypts_to( cipher: &Cipher, - expected: &bitwarden_vault::CipherView, - key: bitwarden_core::key_management::SymmetricKeySlotId, + expected: &CipherView, + key: SymmetricKeySlotId, ctx: &mut bitwarden_crypto::KeyStoreContext, ) { use bitwarden_vault::CipherView; @@ -370,59 +375,6 @@ mod tests { ); } - #[test] - fn test_ciphers() { - let store: KeyStore = KeyStore::default(); - let mut ctx = store.context_mut(); - - let user_key_old = - ctx.make_symmetric_key(bitwarden_crypto::SymmetricKeyAlgorithm::Aes256CbcHmac); - let user_key_new = - ctx.make_symmetric_key(bitwarden_crypto::SymmetricKeyAlgorithm::Aes256CbcHmac); - - let cipher = make_cipher_view(); - let encrypted_cipher = EncryptMode::Legacy(cipher.clone()) - .encrypt_composite(&mut ctx, user_key_old) - .unwrap(); - - // Rotate it - let ciphers = vec![encrypted_cipher]; - let reencrypted_ciphers = - super::reencrypt_ciphers(ciphers.as_slice(), user_key_old, user_key_new, &mut ctx) - .unwrap(); - - // The keyless legacy cipher is upgraded to the blob format and decrypts under the new key - assert!(reencrypted_ciphers[0].is_blob_encrypted()); - assert_decrypts_to(&reencrypted_ciphers[0], &cipher, user_key_new, &mut ctx); - } - - #[test] - fn test_blob_gate_upgrades_keyed_legacy_cipher() { - let store: KeyStore = KeyStore::default(); - let mut ctx = store.context_mut(); - - let user_key_old = - ctx.make_symmetric_key(bitwarden_crypto::SymmetricKeyAlgorithm::Aes256CbcHmac); - let user_key_new = - ctx.make_symmetric_key(bitwarden_crypto::SymmetricKeyAlgorithm::XAes256Gcm); - - // A legacy cipher that already carries a per-item cipher key - let mut cipher = make_cipher_view(); - cipher.generate_cipher_key(&mut ctx, user_key_old).unwrap(); - let encrypted = EncryptMode::Legacy(cipher.clone()) - .encrypt_composite(&mut ctx, user_key_old) - .unwrap(); - assert!(!encrypted.is_blob_encrypted()); - assert!(encrypted.key.is_some()); - - let reencrypted = - super::reencrypt_ciphers(&[encrypted], user_key_old, user_key_new, &mut ctx).unwrap(); - - // The keyed legacy cipher is fully upgraded to the blob format - assert!(reencrypted[0].is_blob_encrypted()); - assert_decrypts_to(&reencrypted[0], &cipher, user_key_new, &mut ctx); - } - #[test] fn test_blob_gate_rewraps_existing_blob_without_re_encrypting() { let store: KeyStore = KeyStore::default(); @@ -536,4 +488,228 @@ mod tests { // The send seed must be the same assert_eq!(send.key, decrypted_send.key); } + + #[test] + fn test_rotation_keyless_plain() { + let store: KeyStore = KeyStore::default(); + let mut ctx = store.context_mut(); + let (old, new) = make_rotation_keys(&mut ctx); + + let cipher = make_rotatable_cipher(&mut ctx, old, false, false, false); + let out = super::reencrypt_ciphers(&[cipher], old, new, &mut ctx).unwrap(); + + assert_upgraded_to_blob(&mut ctx, &out[0], new); + } + + #[test] + fn test_rotation_keyless_fido2() { + let store: KeyStore = KeyStore::default(); + let mut ctx = store.context_mut(); + let (old, new) = make_rotation_keys(&mut ctx); + + let cipher = make_rotatable_cipher(&mut ctx, old, false, false, true); + let out = super::reencrypt_ciphers(&[cipher], old, new, &mut ctx).unwrap(); + + assert_upgraded_to_blob(&mut ctx, &out[0], new); + assert_fido2_decryptable(&mut ctx, &out[0], new); + } + + #[test] + fn test_rotation_keyless_attachment() { + let store: KeyStore = KeyStore::default(); + let mut ctx = store.context_mut(); + let (old, new) = make_rotation_keys(&mut ctx); + + let cipher = make_rotatable_cipher(&mut ctx, old, false, true, false); + let out = super::reencrypt_ciphers(&[cipher], old, new, &mut ctx).unwrap(); + + assert_upgraded_to_blob(&mut ctx, &out[0], new); + assert_attachment_key_decryptable(&mut ctx, &out[0], new); + } + + #[test] + fn test_rotation_keyless_fido2_and_attachment() { + let store: KeyStore = KeyStore::default(); + let mut ctx = store.context_mut(); + let (old, new) = make_rotation_keys(&mut ctx); + + let cipher = make_rotatable_cipher(&mut ctx, old, false, true, true); + let out = super::reencrypt_ciphers(&[cipher], old, new, &mut ctx).unwrap(); + + assert_upgraded_to_blob(&mut ctx, &out[0], new); + assert_fido2_decryptable(&mut ctx, &out[0], new); + assert_attachment_key_decryptable(&mut ctx, &out[0], new); + } + + #[test] + fn test_rotation_keyed_plain() { + let store: KeyStore = KeyStore::default(); + let mut ctx = store.context_mut(); + let (old, new) = make_rotation_keys(&mut ctx); + + let cipher = make_rotatable_cipher(&mut ctx, old, true, false, false); + let out = super::reencrypt_ciphers(&[cipher], old, new, &mut ctx).unwrap(); + + assert_upgraded_to_blob(&mut ctx, &out[0], new); + } + + #[test] + fn test_rotation_keyed_fido2() { + let store: KeyStore = KeyStore::default(); + let mut ctx = store.context_mut(); + let (old, new) = make_rotation_keys(&mut ctx); + + let cipher = make_rotatable_cipher(&mut ctx, old, true, false, true); + let out = super::reencrypt_ciphers(&[cipher], old, new, &mut ctx).unwrap(); + + assert_upgraded_to_blob(&mut ctx, &out[0], new); + assert_fido2_decryptable(&mut ctx, &out[0], new); + } + + #[test] + fn test_rotation_keyed_attachment() { + let store: KeyStore = KeyStore::default(); + let mut ctx = store.context_mut(); + let (old, new) = make_rotation_keys(&mut ctx); + + let cipher = make_rotatable_cipher(&mut ctx, old, true, true, false); + let out = super::reencrypt_ciphers(&[cipher], old, new, &mut ctx).unwrap(); + + assert_upgraded_to_blob(&mut ctx, &out[0], new); + assert_attachment_key_decryptable(&mut ctx, &out[0], new); + } + + #[test] + fn test_rotation_keyed_fido2_and_attachment() { + let store: KeyStore = KeyStore::default(); + let mut ctx = store.context_mut(); + let (old, new) = make_rotation_keys(&mut ctx); + + let cipher = make_rotatable_cipher(&mut ctx, old, true, true, true); + let out = super::reencrypt_ciphers(&[cipher], old, new, &mut ctx).unwrap(); + + assert_upgraded_to_blob(&mut ctx, &out[0], new); + assert_fido2_decryptable(&mut ctx, &out[0], new); + assert_attachment_key_decryptable(&mut ctx, &out[0], new); + } + + /// The old and new user keys for a rotation: two distinct non-`User` slots (so the rotation + /// must honor the explicit keys rather than the cipher's `key_identifier()`), with a change of + /// algorithm mirroring production, which rotates onto an XChaCha20-Poly1305 key. + fn make_rotation_keys( + ctx: &mut bitwarden_crypto::KeyStoreContext, + ) -> (SymmetricKeySlotId, SymmetricKeySlotId) { + let old = ctx.make_symmetric_key(bitwarden_crypto::SymmetricKeyAlgorithm::Aes256CbcHmac); + let new = + ctx.make_symmetric_key(bitwarden_crypto::SymmetricKeyAlgorithm::XChaCha20Poly1305); + (old, new) + } + + /// Builds a legacy personal cipher encrypted under `user_key`, optionally carrying a per-item + /// cipher key, an attachment, and a FIDO2 credential. + fn make_rotatable_cipher( + ctx: &mut bitwarden_crypto::KeyStoreContext, + user_key: SymmetricKeySlotId, + with_cipher_key: bool, + with_attachment: bool, + with_fido2: bool, + ) -> Cipher { + let mut view = make_cipher_view(); + if with_fido2 { + let full = Fido2CredentialFullView { + credential_id: "cred-123".to_string(), + key_type: "public-key".to_string(), + key_algorithm: "ECDSA".to_string(), + key_curve: "P-256".to_string(), + key_value: "key-value".to_string(), + rp_id: "example.com".to_string(), + user_handle: None, + user_name: None, + counter: "0".to_string(), + rp_name: None, + user_display_name: None, + discoverable: "true".to_string(), + creation_date: "2024-06-07T14:12:36.150Z".parse().unwrap(), + }; + view.login.as_mut().unwrap().fido2_credentials = + Some(vec![full.encrypt_composite(ctx, user_key).unwrap()]); + } + if with_cipher_key { + view.upgrade_to_cipher_key_encryption_with_external_key(ctx, user_key, user_key) + .unwrap(); + } + let mut cipher = EncryptMode::Legacy(view) + .encrypt_composite(ctx, user_key) + .unwrap(); + if with_attachment { + // The attachment content key and file name are wrapped under the cipher key: the + // per-item key for a keyed cipher, otherwise the user key directly. + let cipher_key = match &cipher.key { + Some(key) => ctx.unwrap_symmetric_key(user_key, key).unwrap(), + None => user_key, + }; + let content_key = ctx.generate_symmetric_key(); + cipher.attachments = Some(vec![Attachment { + id: Some("att1".to_string()), + url: None, + size: None, + size_name: None, + file_name: Some("secret.txt".encrypt(ctx, cipher_key).unwrap()), + key: Some(ctx.wrap_symmetric_key(cipher_key, content_key).unwrap()), + }]); + } + cipher + } + + /// Asserts the rotated cipher is a blob whose body decrypts under `user_key` to the baseline + /// [`make_cipher_view`] fields. + fn assert_upgraded_to_blob( + ctx: &mut bitwarden_crypto::KeyStoreContext, + rotated: &Cipher, + user_key: SymmetricKeySlotId, + ) { + assert!(rotated.is_blob_encrypted()); + assert_decrypts_to(rotated, &make_cipher_view(), user_key, ctx); + } + + /// Asserts the rotated cipher's FIDO2 credential decrypts to its original values under + /// `user_key`. + fn assert_fido2_decryptable( + ctx: &mut bitwarden_crypto::KeyStoreContext, + rotated: &Cipher, + user_key: SymmetricKeySlotId, + ) { + let dv: CipherView = rotated.decrypt(ctx, user_key).unwrap(); + let cipher_key = ctx + .unwrap_symmetric_key(user_key, dv.key.as_ref().unwrap()) + .unwrap(); + let creds: Vec = dv + .login + .as_ref() + .unwrap() + .fido2_credentials + .as_ref() + .unwrap() + .decrypt(ctx, cipher_key) + .unwrap(); + assert_eq!(creds[0].credential_id, "cred-123"); + assert_eq!(creds[0].key_value, "key-value"); + } + + /// Asserts the rotated cipher's attachment key unwraps under `user_key`. + fn assert_attachment_key_decryptable( + ctx: &mut bitwarden_crypto::KeyStoreContext, + rotated: &Cipher, + user_key: SymmetricKeySlotId, + ) { + let dv: CipherView = rotated.decrypt(ctx, user_key).unwrap(); + let cipher_key = ctx + .unwrap_symmetric_key(user_key, dv.key.as_ref().unwrap()) + .unwrap(); + let att = &dv.attachments.as_ref().unwrap()[0]; + assert_eq!(att.file_name.as_deref(), Some("secret.txt")); + let _ = ctx + .unwrap_symmetric_key(cipher_key, att.key.as_ref().unwrap()) + .expect("attachment key must unwrap under the new cipher key"); + } } diff --git a/crates/bitwarden-vault/src/cipher/blob/encryption.rs b/crates/bitwarden-vault/src/cipher/blob/encryption.rs index ec89b8deb..b0defddc4 100644 --- a/crates/bitwarden-vault/src/cipher/blob/encryption.rs +++ b/crates/bitwarden-vault/src/cipher/blob/encryption.rs @@ -94,7 +94,7 @@ pub(crate) fn encrypt_blob_cipher_with_wrapping_key( wrapping_key: SymmetricKeySlotId, ) -> Result { if view.key.is_none() { - view.generate_cipher_key(ctx, wrapping_key)?; + view.upgrade_to_cipher_key_encryption(ctx, wrapping_key)?; } let cipher_key = Cipher::decrypt_cipher_key(ctx, wrapping_key, &view.key)?; @@ -310,7 +310,7 @@ mod tests { view.secure_note = Some(SecureNoteView { r#type: SecureNoteType::Generic, }); - view.generate_cipher_key(&mut ctx, view.key_identifier()) + view.upgrade_to_cipher_key_encryption(&mut ctx, view.key_identifier()) .unwrap(); let sealed_string = seal_cipher(&view, &mut ctx, view.key_identifier()).unwrap(); diff --git a/crates/bitwarden-vault/src/cipher/cipher.rs b/crates/bitwarden-vault/src/cipher/cipher.rs index 24cd7c924..ac3284345 100644 --- a/crates/bitwarden-vault/src/cipher/cipher.rs +++ b/crates/bitwarden-vault/src/cipher/cipher.rs @@ -904,14 +904,38 @@ impl Cipher { } } impl CipherView { - #[allow(missing_docs)] - pub fn generate_cipher_key( + /// Upgrades the cipher to cipher-key encryption: generates a fresh per-item cipher key and + /// re-wraps the cipher's attachment and FIDO2 sub-keys under it. The existing sub-keys are + /// assumed to be wrapped under [`self.key_identifier()`](IdentifyKey::key_identifier). + pub fn upgrade_to_cipher_key_encryption( &mut self, ctx: &mut KeyStoreContext, wrapping_key: SymmetricKeySlotId, ) -> Result<(), CryptoError> { - let old_unwrapping_key = self.key_identifier(); - let old_ciphers_key = Cipher::decrypt_cipher_key(ctx, old_unwrapping_key, &self.key)?; + self.upgrade_to_cipher_key_encryption_with_external_key( + ctx, + self.key_identifier(), + wrapping_key, + ) + } + + /// Variant of [`upgrade_to_cipher_key_encryption`](Self::upgrade_to_cipher_key_encryption) that + /// unwraps the existing attachment and FIDO2 sub-keys using an explicitly supplied `source_key` + /// rather than deriving it from [`IdentifyKey::key_identifier`]. Use this when the sub-keys are + /// wrapped under a key other than the cipher's identifier — e.g. during key rotation, where + /// they are under the current user key rather than the [`SymmetricKeySlotId::User`] slot. + /// + /// * `source_key` - The key the current attachment/FIDO2 sub-keys are wrapped under. For a + /// keyless cipher this is the current user (or organization) key. + /// * `wrapping_key` - The key the freshly generated cipher key will be wrapped under (during + /// rotation, the new user key). + pub fn upgrade_to_cipher_key_encryption_with_external_key( + &mut self, + ctx: &mut KeyStoreContext, + source_key: SymmetricKeySlotId, + wrapping_key: SymmetricKeySlotId, + ) -> Result<(), CryptoError> { + let old_ciphers_key = Cipher::decrypt_cipher_key(ctx, source_key, &self.key)?; let new_key = ctx.generate_symmetric_key(); @@ -2472,7 +2496,7 @@ mod tests { } #[test] - fn test_generate_cipher_key() { + fn test_upgrade_to_cipher_key_encryption() { let key = SymmetricCryptoKey::make(SymmetricKeyAlgorithm::Aes256CbcHmac); let key_store = create_test_crypto_with_user_key(key); @@ -2487,7 +2511,7 @@ mod tests { let mut cipher = generate_cipher(); cipher - .generate_cipher_key(&mut key_store.context(), cipher.key_identifier()) + .upgrade_to_cipher_key_encryption(&mut key_store.context(), cipher.key_identifier()) .unwrap(); // Check that the cipher gets encrypted correctly when it's assigned it's own key @@ -2498,7 +2522,7 @@ mod tests { } #[test] - fn test_generate_cipher_key_when_a_cipher_key_already_exists() { + fn test_upgrade_to_cipher_key_encryption_when_a_cipher_key_already_exists() { let key = SymmetricCryptoKey::make(SymmetricKeyAlgorithm::Aes256CbcHmac); let key_store = create_test_crypto_with_user_key(key); @@ -2514,7 +2538,10 @@ mod tests { } original_cipher - .generate_cipher_key(&mut key_store.context(), original_cipher.key_identifier()) + .upgrade_to_cipher_key_encryption( + &mut key_store.context(), + original_cipher.key_identifier(), + ) .unwrap(); // Make sure that the cipher key is decryptable @@ -2526,7 +2553,7 @@ mod tests { } #[test] - fn test_generate_cipher_key_ignores_attachments_without_key() { + fn test_upgrade_to_cipher_key_encryption_ignores_attachments_without_key() { let key = SymmetricCryptoKey::make(SymmetricKeyAlgorithm::Aes256CbcHmac); let key_store = create_test_crypto_with_user_key(key); @@ -2544,11 +2571,99 @@ mod tests { cipher.attachments = Some(vec![attachment]); cipher - .generate_cipher_key(&mut key_store.context(), cipher.key_identifier()) + .upgrade_to_cipher_key_encryption(&mut key_store.context(), cipher.key_identifier()) .unwrap(); assert!(cipher.attachments.unwrap()[0].key.is_none()); } + #[test] + fn test_upgrade_to_cipher_key_encryption_with_external_key_rewraps_fido2_credentials() { + use crate::cipher::login::Fido2CredentialFullView; + + let key_store = create_test_crypto_with_user_key(SymmetricCryptoKey::make( + SymmetricKeyAlgorithm::Aes256CbcHmac, + )); + let mut ctx = key_store.context_mut(); + + // Local slots, distinct from the cipher's `key_identifier()` (`User`). + let source_key = ctx.add_local_symmetric_key(SymmetricCryptoKey::make( + SymmetricKeyAlgorithm::Aes256CbcHmac, + )); + let new_user_key = ctx.add_local_symmetric_key(SymmetricCryptoKey::make( + SymmetricKeyAlgorithm::Aes256CbcHmac, + )); + + // Keyless cipher whose FIDO2 credential is wrapped under `source_key`. + let mut cipher = generate_cipher(); + cipher.login.as_mut().unwrap().fido2_credentials = + Some(vec![generate_fido2(&mut ctx, source_key)]); + assert!(cipher.key.is_none()); + + cipher + .upgrade_to_cipher_key_encryption_with_external_key(&mut ctx, source_key, new_user_key) + .unwrap(); + + // The FIDO2 credential decrypts under the freshly installed cipher key. + let cipher_key = Cipher::decrypt_cipher_key(&mut ctx, new_user_key, &cipher.key).unwrap(); + let creds: Vec = cipher + .login + .as_ref() + .unwrap() + .fido2_credentials + .as_ref() + .unwrap() + .decrypt(&mut ctx, cipher_key) + .unwrap(); + assert_eq!(creds[0].credential_id, "123"); + } + + #[test] + fn test_upgrade_to_cipher_key_encryption_with_external_key_rewraps_attachment_key() { + let key_store = create_test_crypto_with_user_key(SymmetricCryptoKey::make( + SymmetricKeyAlgorithm::Aes256CbcHmac, + )); + let mut ctx = key_store.context_mut(); + + // Local slots, distinct from the cipher's `key_identifier()` (`User`). + let source_key = ctx.add_local_symmetric_key(SymmetricCryptoKey::make( + SymmetricKeyAlgorithm::Aes256CbcHmac, + )); + let new_user_key = ctx.add_local_symmetric_key(SymmetricCryptoKey::make( + SymmetricKeyAlgorithm::Aes256CbcHmac, + )); + + // Keyless cipher whose attachment key is wrapped under `source_key`. + let content_key = ctx.generate_symmetric_key(); + let mut cipher = generate_cipher(); + cipher.attachments = Some(vec![AttachmentView { + id: None, + url: None, + size: None, + size_name: None, + file_name: Some("secret.txt".into()), + key: Some(ctx.wrap_symmetric_key(source_key, content_key).unwrap()), + #[cfg(feature = "wasm")] + decrypted_key: None, + }]); + assert!(cipher.key.is_none()); + + cipher + .upgrade_to_cipher_key_encryption_with_external_key(&mut ctx, source_key, new_user_key) + .unwrap(); + + // The attachment key unwraps under the freshly installed cipher key. + let cipher_key = Cipher::decrypt_cipher_key(&mut ctx, new_user_key, &cipher.key).unwrap(); + let _ = ctx + .unwrap_symmetric_key( + cipher_key, + cipher.attachments.as_ref().unwrap()[0] + .key + .as_ref() + .unwrap(), + ) + .expect("attachment key must unwrap under the new cipher key"); + } + #[test] fn test_reencrypt_cipher_key() { let old_key = SymmetricCryptoKey::make(SymmetricKeyAlgorithm::Aes256CbcHmac); @@ -2558,7 +2673,7 @@ mod tests { let mut cipher = generate_cipher(); cipher - .generate_cipher_key(&mut ctx, cipher.key_identifier()) + .upgrade_to_cipher_key_encryption(&mut ctx, cipher.key_identifier()) .unwrap(); // Re-encrypt the cipher key with a new wrapping key @@ -2601,7 +2716,7 @@ mod tests { // Create a cipher with a user key let mut cipher = generate_cipher(); cipher - .generate_cipher_key(&mut key_store.context(), cipher.key_identifier()) + .upgrade_to_cipher_key_encryption(&mut key_store.context(), cipher.key_identifier()) .unwrap(); cipher @@ -2626,7 +2741,7 @@ mod tests { // Create a cipher with a user key let mut cipher = generate_cipher(); cipher - .generate_cipher_key(&mut key_store.context(), cipher.key_identifier()) + .upgrade_to_cipher_key_encryption(&mut key_store.context(), cipher.key_identifier()) .unwrap(); cipher.organization_id = Some(org); @@ -2821,7 +2936,7 @@ mod tests { let mut cipher_view = generate_cipher(); cipher_view - .generate_cipher_key(&mut ctx, cipher_view.key_identifier()) + .upgrade_to_cipher_key_encryption(&mut ctx, cipher_view.key_identifier()) .unwrap(); let key_id = cipher_view.key_identifier(); diff --git a/crates/bitwarden-vault/src/cipher/cipher_client/admin/create.rs b/crates/bitwarden-vault/src/cipher/cipher_client/admin/create.rs index 454100609..147701aab 100644 --- a/crates/bitwarden-vault/src/cipher/cipher_client/admin/create.rs +++ b/crates/bitwarden-vault/src/cipher/cipher_client/admin/create.rs @@ -116,7 +116,7 @@ impl CipherAdminClient { // be moved directly into the CompositeEncryptable implementation. if self.client.flags().get().await.enable_cipher_key_encryption { let key = view.key_identifier(); - view.generate_cipher_key(&mut key_store.context(), key)?; + view.upgrade_to_cipher_key_encryption(&mut key_store.context(), key)?; } let use_blob = should_use_blob_encryption(&key_store.context(), view.organization_id); diff --git a/crates/bitwarden-vault/src/cipher/cipher_client/admin/edit.rs b/crates/bitwarden-vault/src/cipher/cipher_client/admin/edit.rs index 6af53b37e..c5f737a1f 100644 --- a/crates/bitwarden-vault/src/cipher/cipher_client/admin/edit.rs +++ b/crates/bitwarden-vault/src/cipher/cipher_client/admin/edit.rs @@ -80,7 +80,7 @@ async fn edit_cipher( // moved directly into the CompositeEncryptable implementation. if view.key.is_none() && enable_cipher_key_encryption { let key = view.key_identifier(); - view.generate_cipher_key(&mut key_store.context(), key)?; + view.upgrade_to_cipher_key_encryption(&mut key_store.context(), key)?; } // Admin endpoints operate on organization-owned ciphers, which aren't diff --git a/crates/bitwarden-vault/src/cipher/cipher_client/create.rs b/crates/bitwarden-vault/src/cipher/cipher_client/create.rs index bca97b8a0..321a42f78 100644 --- a/crates/bitwarden-vault/src/cipher/cipher_client/create.rs +++ b/crates/bitwarden-vault/src/cipher/cipher_client/create.rs @@ -183,7 +183,7 @@ impl CiphersClient { // be moved directly into the CompositeEncryptable implementation. if self.client.flags().get().await.enable_cipher_key_encryption { let key = view.key_identifier(); - view.generate_cipher_key(&mut key_store.context(), key)?; + view.upgrade_to_cipher_key_encryption(&mut key_store.context(), key)?; } let use_blob = self.should_use_blob_encryption(view.organization_id); diff --git a/crates/bitwarden-vault/src/cipher/cipher_client/edit.rs b/crates/bitwarden-vault/src/cipher/cipher_client/edit.rs index 521066541..d35b81b1a 100644 --- a/crates/bitwarden-vault/src/cipher/cipher_client/edit.rs +++ b/crates/bitwarden-vault/src/cipher/cipher_client/edit.rs @@ -195,7 +195,7 @@ async fn edit_cipher + ?Sized>( // moved directly into the CompositeEncryptable implementation. if view.key.is_none() && enable_cipher_key_encryption { let key = view.key_identifier(); - view.generate_cipher_key(&mut key_store.context(), key)?; + view.upgrade_to_cipher_key_encryption(&mut key_store.context(), key)?; } let mode = if use_blob { diff --git a/crates/bitwarden-vault/src/cipher/cipher_client/mod.rs b/crates/bitwarden-vault/src/cipher/cipher_client/mod.rs index 11385171e..0ec4b7af6 100644 --- a/crates/bitwarden-vault/src/cipher/cipher_client/mod.rs +++ b/crates/bitwarden-vault/src/cipher/cipher_client/mod.rs @@ -99,7 +99,7 @@ impl CiphersClient { if cipher_view.key.is_none() && self.client.flags().get().await.enable_cipher_key_encryption { let key = cipher_view.key_identifier(); - cipher_view.generate_cipher_key(&mut key_store.context(), key)?; + cipher_view.upgrade_to_cipher_key_encryption(&mut key_store.context(), key)?; } let mode = if self.should_use_blob_encryption(cipher_view.organization_id) { @@ -147,7 +147,7 @@ impl CiphersClient { let new_key_id = ctx.add_local_symmetric_key(new_key); if cipher_view.key.is_none() && enable_cipher_key_encryption { - cipher_view.generate_cipher_key(&mut ctx, new_key_id)?; + cipher_view.upgrade_to_cipher_key_encryption(&mut ctx, new_key_id)?; } else { cipher_view.reencrypt_cipher_keys(&mut ctx, new_key_id)?; } @@ -192,7 +192,7 @@ impl CiphersClient { .map(|mut cv| { if cv.key.is_none() && enable_cipher_key { let key = cv.key_identifier(); - cv.generate_cipher_key(&mut ctx, key)?; + cv.upgrade_to_cipher_key_encryption(&mut ctx, key)?; } let mode = if self.should_use_blob_encryption(cv.organization_id) { EncryptMode::Blob(cv)