diff --git a/crates/bitwarden-core/src/client/internal.rs b/crates/bitwarden-core/src/client/internal.rs index 591041177..ad9b3276d 100644 --- a/crates/bitwarden-core/src/client/internal.rs +++ b/crates/bitwarden-core/src/client/internal.rs @@ -4,7 +4,10 @@ use bitwarden_crypto::KeyStore; #[cfg(any(feature = "internal", feature = "secrets"))] use bitwarden_crypto::SymmetricCryptoKey; #[cfg(feature = "internal")] -use bitwarden_crypto::{CryptoError, EncString, Kdf, MasterKey, PinKey, UnsignedSharedKey}; +use bitwarden_crypto::{ + CryptoError, EncString, Kdf, MasterKey, PinKey, UnsignedSharedKey, + safe::PasswordProtectedKeyEnvelope, +}; #[cfg(feature = "internal")] use bitwarden_state::registry::StateRegistry; use chrono::Utc; @@ -25,10 +28,7 @@ use crate::{ login_method::UserLoginMethod, }, error::NotAuthenticatedError, - key_management::{ - PasswordProtectedKeyEnvelope, SecurityState, SignedSecurityState, - crypto::InitUserCryptoRequest, - }, + key_management::{SecurityState, SignedSecurityState, crypto::InitUserCryptoRequest}, }; /// Represents the user's keys, that are encrypted by the user key, and the signed security state. diff --git a/crates/bitwarden-core/src/key_management/crypto.rs b/crates/bitwarden-core/src/key_management/crypto.rs index aa53b9245..f9a6e9199 100644 --- a/crates/bitwarden-core/src/key_management/crypto.rs +++ b/crates/bitwarden-core/src/key_management/crypto.rs @@ -10,7 +10,8 @@ use bitwarden_crypto::{ AsymmetricCryptoKey, CoseSerializable, CryptoError, EncString, Kdf, KeyDecryptable, KeyEncryptable, MasterKey, Pkcs8PrivateKeyBytes, PrimitiveEncryptable, SignatureAlgorithm, SignedPublicKey, SigningKey, SpkiPublicKeyBytes, SymmetricCryptoKey, UnsignedSharedKey, - UserKey, dangerous_get_v2_rotated_account_keys, safe::PasswordProtectedKeyEnvelopeError, + UserKey, dangerous_get_v2_rotated_account_keys, + safe::{PasswordProtectedKeyEnvelope, PasswordProtectedKeyEnvelopeError}, }; use bitwarden_encoding::B64; use bitwarden_error::bitwarden_error; @@ -26,7 +27,6 @@ use crate::{ key_management::{ AsymmetricKeyId, SecurityState, SignedSecurityState, SigningKeyId, SymmetricKeyId, master_password::{MasterPasswordAuthenticationData, MasterPasswordUnlockData}, - non_generic_wrappers::PasswordProtectedKeyEnvelope, }, }; @@ -412,12 +412,7 @@ pub(super) fn enroll_pin( let key_store = client.internal.get_key_store(); let mut ctx = key_store.context_mut(); - let key_envelope = - PasswordProtectedKeyEnvelope(bitwarden_crypto::safe::PasswordProtectedKeyEnvelope::seal( - SymmetricKeyId::User, - &pin, - &ctx, - )?); + let key_envelope = PasswordProtectedKeyEnvelope::seal(SymmetricKeyId::User, &pin, &ctx)?; let encrypted_pin = pin.encrypt(&mut ctx, SymmetricKeyId::User)?; Ok(EnrollPinResponse { pin_protected_user_key_envelope: key_envelope, diff --git a/crates/bitwarden-core/src/key_management/crypto_client.rs b/crates/bitwarden-core/src/key_management/crypto_client.rs index 08a18168f..fcdf1afeb 100644 --- a/crates/bitwarden-core/src/key_management/crypto_client.rs +++ b/crates/bitwarden-core/src/key_management/crypto_client.rs @@ -1,6 +1,6 @@ use bitwarden_crypto::{CryptoError, Decryptable, Kdf}; #[cfg(feature = "internal")] -use bitwarden_crypto::{EncString, UnsignedSharedKey}; +use bitwarden_crypto::{EncString, UnsignedSharedKey, safe::PasswordProtectedKeyEnvelope}; use bitwarden_encoding::B64; #[cfg(feature = "wasm")] use wasm_bindgen::prelude::*; @@ -10,8 +10,6 @@ use super::crypto::{ MakeKeyPairResponse, VerifyAsymmetricKeysRequest, VerifyAsymmetricKeysResponse, derive_key_connector, make_key_pair, verify_asymmetric_keys, }; -#[cfg(any(feature = "wasm", test))] -use crate::key_management::PasswordProtectedKeyEnvelope; #[cfg(feature = "internal")] use crate::key_management::{ SymmetricKeyId, diff --git a/crates/bitwarden-core/src/key_management/mod.rs b/crates/bitwarden-core/src/key_management/mod.rs index a7718cdfe..7b02254e7 100644 --- a/crates/bitwarden-core/src/key_management/mod.rs +++ b/crates/bitwarden-core/src/key_management/mod.rs @@ -22,10 +22,6 @@ pub use crypto_client::CryptoClient; #[cfg(feature = "internal")] mod master_password; #[cfg(feature = "internal")] -mod non_generic_wrappers; -#[cfg(feature = "internal")] -pub(crate) use non_generic_wrappers::*; -#[cfg(feature = "internal")] mod security_state; #[cfg(feature = "internal")] mod user_decryption; diff --git a/crates/bitwarden-core/src/key_management/non_generic_wrappers.rs b/crates/bitwarden-core/src/key_management/non_generic_wrappers.rs deleted file mode 100644 index cb666a304..000000000 --- a/crates/bitwarden-core/src/key_management/non_generic_wrappers.rs +++ /dev/null @@ -1,36 +0,0 @@ -//! Structs with generic parameters cannot be moved across FFI bounds (uniffi/wasm). -//! This module contains wrapper structs that hide the generic parameter with instantiated versions. - -use std::ops::Deref; - -use serde::{Deserialize, Serialize}; -#[cfg(feature = "wasm")] -use tsify::Tsify; - -use crate::key_management::KeyIds; - -/// A non-generic wrapper around `bitwarden-crypto`'s `PasswordProtectedKeyEnvelope`. -#[derive(Serialize, Deserialize)] -#[serde(transparent)] -#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] -pub struct PasswordProtectedKeyEnvelope( - #[cfg_attr( - feature = "wasm", - tsify(type = r#"Tagged"#) - )] - pub(crate) bitwarden_crypto::safe::PasswordProtectedKeyEnvelope, -); - -impl Deref for PasswordProtectedKeyEnvelope { - type Target = bitwarden_crypto::safe::PasswordProtectedKeyEnvelope; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl std::fmt::Debug for PasswordProtectedKeyEnvelope { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.0.fmt(f) - } -} diff --git a/crates/bitwarden-core/src/uniffi_support.rs b/crates/bitwarden-core/src/uniffi_support.rs index 6a24dd437..ea70c6815 100644 --- a/crates/bitwarden-core/src/uniffi_support.rs +++ b/crates/bitwarden-core/src/uniffi_support.rs @@ -2,10 +2,11 @@ use std::{num::NonZeroU32, str::FromStr}; +use bitwarden_crypto::safe::PasswordProtectedKeyEnvelope; use bitwarden_uniffi_error::convert_result; use uuid::Uuid; -use crate::key_management::{PasswordProtectedKeyEnvelope, SignedSecurityState}; +use crate::key_management::SignedSecurityState; uniffi::use_remote_type!(bitwarden_crypto::NonZeroU32); @@ -36,7 +37,6 @@ uniffi::custom_type!(SignedSecurityState, String, { uniffi::custom_type!(PasswordProtectedKeyEnvelope, String, { remote, - try_lift: |val| convert_result(bitwarden_crypto::safe::PasswordProtectedKeyEnvelope::from_str(&val) - .map(PasswordProtectedKeyEnvelope)), - lower: |obj| obj.0.into(), + try_lift: |val| convert_result(PasswordProtectedKeyEnvelope::from_str(&val)), + lower: |obj| obj.into(), }); diff --git a/crates/bitwarden-crypto/examples/protect_key_with_password.rs b/crates/bitwarden-crypto/examples/protect_key_with_password.rs index 5c80cfc33..474fdeb8f 100644 --- a/crates/bitwarden-crypto/examples/protect_key_with_password.rs +++ b/crates/bitwarden-crypto/examples/protect_key_with_password.rs @@ -36,12 +36,11 @@ fn main() { ctx.clear_local(); // Load the envelope from disk and unseal it with the PIN, and store it in the context. - let deserialized: PasswordProtectedKeyEnvelope = - PasswordProtectedKeyEnvelope::try_from( - disk.load("vault_key_envelope") - .expect("Loading from disk should work"), - ) - .expect("Deserializing envelope should work"); + let deserialized: PasswordProtectedKeyEnvelope = PasswordProtectedKeyEnvelope::try_from( + disk.load("vault_key_envelope") + .expect("Loading from disk should work"), + ) + .expect("Deserializing envelope should work"); deserialized .unseal(ExampleSymmetricKey::VaultKey, pin, &mut ctx) .expect("Unsealing should work"); diff --git a/crates/bitwarden-crypto/src/safe/password_protected_key_envelope.rs b/crates/bitwarden-crypto/src/safe/password_protected_key_envelope.rs index e3cf46f26..5711a6aa3 100644 --- a/crates/bitwarden-crypto/src/safe/password_protected_key_envelope.rs +++ b/crates/bitwarden-crypto/src/safe/password_protected_key_envelope.rs @@ -13,7 +13,7 @@ //! single recipient's unprotected headers. The output from the KDF - "envelope key", is used to //! wrap the symmetric key, that is sealed by the envelope. -use std::{marker::PhantomData, num::TryFromIntError, str::FromStr}; +use std::{num::TryFromIntError, str::FromStr}; use argon2::Params; use bitwarden_encoding::{B64, FromStrVisitor}; @@ -22,6 +22,8 @@ use coset::{CborSerializable, CoseError, Header, HeaderBuilder}; use rand::RngCore; use serde::{Deserialize, Serialize}; use thiserror::Error; +#[cfg(feature = "wasm")] +use tsify::Tsify; use crate::{ BitwardenLegacyKeyBytes, ContentFormat, CoseKeyBytes, EncodedSymmetricKey, KeyIds, @@ -47,17 +49,17 @@ const ENVELOPE_ARGON2_OUTPUT_KEY_SIZE: usize = 32; /// be provided. /// /// Internally, Argon2 is used as the KDF and XChaCha20-Poly1305 is used to encrypt the key. -pub struct PasswordProtectedKeyEnvelope { - _phantom: PhantomData, +#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] +pub struct PasswordProtectedKeyEnvelope { cose_encrypt: coset::CoseEncrypt, } -impl PasswordProtectedKeyEnvelope { +impl PasswordProtectedKeyEnvelope { /// Seals a symmetric key with a password, using the current default KDF parameters and a random /// salt. /// /// This should never fail, except for memory allocation error, when running the KDF. - pub fn seal( + pub fn seal( key_to_seal: Ids::Symmetric, password: &str, ctx: &KeyStoreContext, @@ -129,15 +131,12 @@ impl PasswordProtectedKeyEnvelope { .build(); cose_encrypt.unprotected.iv = nonce.into(); - Ok(PasswordProtectedKeyEnvelope { - _phantom: PhantomData, - cose_encrypt, - }) + Ok(PasswordProtectedKeyEnvelope { cose_encrypt }) } /// Unseals a symmetric key from the password-protected envelope, and stores it in the key store /// context. - pub fn unseal( + pub fn unseal( &self, target_keyslot: Ids::Symmetric, password: &str, @@ -229,8 +228,8 @@ impl PasswordProtectedKeyEnvelope { } } -impl From<&PasswordProtectedKeyEnvelope> for Vec { - fn from(val: &PasswordProtectedKeyEnvelope) -> Self { +impl From<&PasswordProtectedKeyEnvelope> for Vec { + fn from(val: &PasswordProtectedKeyEnvelope) -> Self { val.cose_encrypt .clone() .to_vec() @@ -238,19 +237,16 @@ impl From<&PasswordProtectedKeyEnvelope> for Vec { } } -impl TryFrom<&Vec> for PasswordProtectedKeyEnvelope { +impl TryFrom<&Vec> for PasswordProtectedKeyEnvelope { type Error = CoseError; fn try_from(value: &Vec) -> Result { let cose_encrypt = coset::CoseEncrypt::from_slice(value)?; - Ok(PasswordProtectedKeyEnvelope { - _phantom: PhantomData, - cose_encrypt, - }) + Ok(PasswordProtectedKeyEnvelope { cose_encrypt }) } } -impl std::fmt::Debug for PasswordProtectedKeyEnvelope { +impl std::fmt::Debug for PasswordProtectedKeyEnvelope { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("PasswordProtectedKeyEnvelope") .field("cose_encrypt", &self.cose_encrypt) @@ -258,7 +254,7 @@ impl std::fmt::Debug for PasswordProtectedKeyEnvelope { } } -impl FromStr for PasswordProtectedKeyEnvelope { +impl FromStr for PasswordProtectedKeyEnvelope { type Err = PasswordProtectedKeyEnvelopeError; fn from_str(s: &str) -> Result { @@ -275,14 +271,14 @@ impl FromStr for PasswordProtectedKeyEnvelope { } } -impl From> for String { - fn from(val: PasswordProtectedKeyEnvelope) -> Self { +impl From for String { + fn from(val: PasswordProtectedKeyEnvelope) -> Self { let serialized: Vec = (&val).into(); B64::from(serialized).to_string() } } -impl<'de, Ids: KeyIds> Deserialize<'de> for PasswordProtectedKeyEnvelope { +impl<'de> Deserialize<'de> for PasswordProtectedKeyEnvelope { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, @@ -291,7 +287,7 @@ impl<'de, Ids: KeyIds> Deserialize<'de> for PasswordProtectedKeyEnvelope { } } -impl Serialize for PasswordProtectedKeyEnvelope { +impl Serialize for PasswordProtectedKeyEnvelope { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, @@ -547,7 +543,7 @@ mod tests { let serialized: Vec = (&envelope).into(); // Unseal the key from the envelope - let deserialized: PasswordProtectedKeyEnvelope = + let deserialized: PasswordProtectedKeyEnvelope = PasswordProtectedKeyEnvelope::try_from(&serialized).unwrap(); deserialized .unseal(TestSymmKey::A(1), password, &mut ctx) @@ -580,7 +576,7 @@ mod tests { let serialized: Vec = (&envelope).into(); // Unseal the key from the envelope - let deserialized: PasswordProtectedKeyEnvelope = + let deserialized: PasswordProtectedKeyEnvelope = PasswordProtectedKeyEnvelope::try_from(&serialized).unwrap(); deserialized .unseal(TestSymmKey::A(1), password, &mut ctx) @@ -607,7 +603,7 @@ mod tests { let new_password = "new_test_password"; // Seal the key with a password - let envelope: PasswordProtectedKeyEnvelope = + let envelope: PasswordProtectedKeyEnvelope = PasswordProtectedKeyEnvelope::seal_ref(&key, password).expect("Sealing should work"); // Reseal @@ -635,7 +631,7 @@ mod tests { let envelope = PasswordProtectedKeyEnvelope::seal(test_key, password, &ctx).unwrap(); // Attempt to unseal with the wrong password - let deserialized: PasswordProtectedKeyEnvelope = + let deserialized: PasswordProtectedKeyEnvelope = PasswordProtectedKeyEnvelope::try_from(&(&envelope).into()).unwrap(); assert!(matches!( deserialized.unseal(TestSymmKey::A(1), wrong_password, &mut ctx), diff --git a/crates/bitwarden-crypto/src/uniffi_support.rs b/crates/bitwarden-crypto/src/uniffi_support.rs index 9f1984fc6..70d66c5eb 100644 --- a/crates/bitwarden-crypto/src/uniffi_support.rs +++ b/crates/bitwarden-crypto/src/uniffi_support.rs @@ -2,7 +2,9 @@ use std::{num::NonZeroU32, str::FromStr}; use bitwarden_uniffi_error::convert_result; -use crate::{CryptoError, EncString, SignedPublicKey, UnsignedSharedKey}; +use crate::{ + CryptoError, EncString, SignedPublicKey, UnsignedSharedKey, safe::PasswordProtectedKeyEnvelope, +}; uniffi::custom_type!(NonZeroU32, u32, { remote, @@ -32,3 +34,9 @@ uniffi::custom_type!(SignedPublicKey, String, { }, lower: |obj| obj.into(), }); + +uniffi::custom_type!(PasswordProtectedKeyEnvelope, String, { + remote, + try_lift: |val| convert_result(PasswordProtectedKeyEnvelope::from_str(&val)), + lower: |obj| obj.into(), +});