From 92ecdbe169332d73912d026571cd0e778fa65be6 Mon Sep 17 00:00:00 2001 From: Maciej Zieniuk Date: Sun, 21 Sep 2025 23:42:34 +0100 Subject: [PATCH 1/3] adds decrypt_user_key_with_master_key into PureCrypto --- .../src/pure_crypto.rs | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/crates/bitwarden-wasm-internal/src/pure_crypto.rs b/crates/bitwarden-wasm-internal/src/pure_crypto.rs index eb1aefa7e..6abd03fef 100644 --- a/crates/bitwarden-wasm-internal/src/pure_crypto.rs +++ b/crates/bitwarden-wasm-internal/src/pure_crypto.rs @@ -323,13 +323,26 @@ impl PureCrypto { #[allow(deprecated)] dangerous_derive_kdf_material(password, salt, &kdf) } + + pub fn decrypt_user_key_with_master_key( + encrypted_user_key: String, + master_key: Vec, + ) -> Result, CryptoError> { + let master_key = &BitwardenLegacyKeyBytes::from(master_key); + let master_key = &SymmetricCryptoKey::try_from(master_key)?; + let master_key = MasterKey::try_from(master_key).map_err(|_| CryptoError::InvalidKey)?; + let encrypted_user_key = EncString::from_str(&encrypted_user_key)?; + let result = master_key + .decrypt_user_key(encrypted_user_key) + .map_err(|_| CryptoError::InvalidKey)?; + Ok(result.to_encoded().to_vec()) + } } #[cfg(test)] mod tests { - use std::{num::NonZero, str::FromStr}; - use bitwarden_crypto::EncString; + use std::{num::NonZero, str::FromStr}; use super::*; @@ -665,4 +678,25 @@ DnqOsltgPomWZ7xVfMkm9niL2OA= let derived_key = PureCrypto::derive_kdf_material(password, email, kdf).unwrap(); assert_eq!(derived_key, DERIVED_KDF_MATERIAL_ARGON2ID); } + + #[test] + fn test_decrypt_user_key_with_master_key() { + let password = "test_password"; + let email = "test_email@example.com"; + let kdf = &Kdf::Argon2id { + iterations: NonZero::try_from(3).unwrap(), + memory: NonZero::try_from(64).unwrap(), + parallelism: NonZero::try_from(4).unwrap(), + }; + let master_key = MasterKey::derive(password, email, kdf).unwrap(); + let (user_key, encrypted_user_key) = master_key.make_user_key().unwrap(); + let master_key_bytes = master_key.to_base64().into_bytes(); + + let decrypted_user_key = PureCrypto::decrypt_user_key_with_master_key( + encrypted_user_key.to_string(), + master_key_bytes, + ) + .unwrap(); + assert_eq!(user_key.0.to_encoded().to_vec(), decrypted_user_key); + } } From a89da1a4661b1c24a3ef9970af11a8aa5581d9f1 Mon Sep 17 00:00:00 2001 From: Maciej Zieniuk Date: Sun, 21 Sep 2025 23:45:57 +0100 Subject: [PATCH 2/3] lint --- crates/bitwarden-wasm-internal/src/pure_crypto.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/bitwarden-wasm-internal/src/pure_crypto.rs b/crates/bitwarden-wasm-internal/src/pure_crypto.rs index 6abd03fef..991076639 100644 --- a/crates/bitwarden-wasm-internal/src/pure_crypto.rs +++ b/crates/bitwarden-wasm-internal/src/pure_crypto.rs @@ -341,9 +341,10 @@ impl PureCrypto { #[cfg(test)] mod tests { - use bitwarden_crypto::EncString; use std::{num::NonZero, str::FromStr}; + use bitwarden_crypto::EncString; + use super::*; const KEY: &[u8] = &[ From 59df3cb625490c7a00334f7c831525409b48fb93 Mon Sep 17 00:00:00 2001 From: Maciej Zieniuk Date: Mon, 22 Sep 2025 15:56:58 +0100 Subject: [PATCH 3/3] necessary map_err cleanup --- crates/bitwarden-wasm-internal/src/pure_crypto.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bitwarden-wasm-internal/src/pure_crypto.rs b/crates/bitwarden-wasm-internal/src/pure_crypto.rs index 991076639..d28ac55ff 100644 --- a/crates/bitwarden-wasm-internal/src/pure_crypto.rs +++ b/crates/bitwarden-wasm-internal/src/pure_crypto.rs @@ -330,7 +330,7 @@ impl PureCrypto { ) -> Result, CryptoError> { let master_key = &BitwardenLegacyKeyBytes::from(master_key); let master_key = &SymmetricCryptoKey::try_from(master_key)?; - let master_key = MasterKey::try_from(master_key).map_err(|_| CryptoError::InvalidKey)?; + let master_key = MasterKey::try_from(master_key)?; let encrypted_user_key = EncString::from_str(&encrypted_user_key)?; let result = master_key .decrypt_user_key(encrypted_user_key)