Skip to content

Unify WASM crypto client with mobile #226

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions crates/bitwarden-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ uniffi = ["bitwarden-crypto/uniffi", "dep:uniffi"] # Uniffi bindings
wasm = [
"bitwarden-error/wasm",
"dep:wasm-bindgen",
"dep:wasm-bindgen-futures",
"dep:tsify-next"
] # WASM support

Expand All @@ -49,6 +50,7 @@ tsify-next = { workspace = true, optional = true }
uniffi = { workspace = true, optional = true, features = ["tokio"] }
uuid = { workspace = true }
wasm-bindgen = { workspace = true, optional = true }
wasm-bindgen-futures = { workspace = true, optional = true }
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This dep is used internally for the wasm-bindgen macro as cryptoclient has some async functions.

zeroize = { version = ">=1.7.0, <2.0", features = ["derive", "aarch64"] }
zxcvbn = { version = ">=3.0.1, <4.0", optional = true }

Expand Down
9 changes: 9 additions & 0 deletions crates/bitwarden-core/src/mobile/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
AsymmetricCryptoKey, CryptoError, EncString, Kdf, KeyDecryptable, KeyEncryptable, MasterKey,
SymmetricCryptoKey, UnsignedSharedKey, UserKey,
};
use bitwarden_error::bitwarden_error;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[cfg(feature = "wasm")]
Expand All @@ -24,6 +25,7 @@

/// Catch all error for mobile crypto operations.
#[allow(missing_docs)]
#[bitwarden_error(flat)]

Check warning on line 28 in crates/bitwarden-core/src/mobile/crypto.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-core/src/mobile/crypto.rs#L28

Added line #L28 was not covered by tests
#[derive(Debug, thiserror::Error)]
pub enum MobileCryptoError {
#[error(transparent)]
Expand Down Expand Up @@ -255,6 +257,7 @@
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct UpdatePasswordResponse {
/// Hash of the new password
password_hash: String,
Expand Down Expand Up @@ -304,6 +307,7 @@
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct DerivePinKeyResponse {
/// [UserKey] protected by PIN
pin_protected_user_key: EncString,
Expand Down Expand Up @@ -373,6 +377,7 @@
}

#[allow(missing_docs)]
#[bitwarden_error(flat)]

Check warning on line 380 in crates/bitwarden-core/src/mobile/crypto.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-core/src/mobile/crypto.rs#L380

Added line #L380 was not covered by tests
#[derive(Debug, thiserror::Error)]
pub enum EnrollAdminPasswordResetError {
#[error(transparent)]
Expand Down Expand Up @@ -404,7 +409,10 @@
}

/// Request for migrating an account from password to key connector.
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub struct DeriveKeyConnectorRequest {
/// Encrypted user key, used to validate the master key
pub user_key_encrypted: EncString,
Expand All @@ -417,6 +425,7 @@
}

#[allow(missing_docs)]
#[bitwarden_error(flat)]

Check warning on line 428 in crates/bitwarden-core/src/mobile/crypto.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-core/src/mobile/crypto.rs#L428

Added line #L428 was not covered by tests
#[derive(Debug, thiserror::Error)]
pub enum DeriveKeyConnectorError {
#[error(transparent)]
Expand Down
37 changes: 22 additions & 15 deletions crates/bitwarden-core/src/mobile/crypto_client.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use bitwarden_crypto::CryptoError;
#[cfg(feature = "internal")]
use bitwarden_crypto::{EncString, UnsignedSharedKey};
#[cfg(feature = "wasm")]
use wasm_bindgen::prelude::*;

use super::crypto::{
derive_key_connector, make_key_pair, verify_asymmetric_keys, DeriveKeyConnectorError,
Expand All @@ -16,10 +18,12 @@
use crate::{client::encryption_settings::EncryptionSettingsError, Client};

/// A client for the crypto operations.
#[cfg_attr(feature = "wasm", wasm_bindgen)]
pub struct CryptoClient {
pub(crate) client: crate::Client,
}

#[cfg_attr(feature = "wasm", wasm_bindgen)]
impl CryptoClient {
/// Initialization method for the user crypto. Needs to be called before any other crypto
/// operations.
Expand All @@ -39,6 +43,24 @@
initialize_org_crypto(&self.client, req).await
}

/// Generates a new key pair and encrypts the private key with the provided user key.
/// Crypto initialization not required.
pub fn make_key_pair(&self, user_key: String) -> Result<MakeKeyPairResponse, CryptoError> {
make_key_pair(user_key)
}

Check warning on line 50 in crates/bitwarden-core/src/mobile/crypto_client.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-core/src/mobile/crypto_client.rs#L48-L50

Added lines #L48 - L50 were not covered by tests

/// Verifies a user's asymmetric keys by decrypting the private key with the provided user
/// key. Returns if the private key is decryptable and if it is a valid matching key.
/// Crypto initialization not required.
pub fn verify_asymmetric_keys(
&self,
request: VerifyAsymmetricKeysRequest,
) -> Result<VerifyAsymmetricKeysResponse, CryptoError> {
verify_asymmetric_keys(request)
}

Check warning on line 60 in crates/bitwarden-core/src/mobile/crypto_client.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-core/src/mobile/crypto_client.rs#L55-L60

Added lines #L55 - L60 were not covered by tests
}

impl CryptoClient {
Copy link
Member Author

@dani-garcia dani-garcia Apr 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've split the impl CryptoClient into two blocks, one with wasm_bindgen for the functions we're currently exporting to wasm, and one without it for the ones that we're not using.

We could also export all of them if we wanted, but to keep the PR simple I only include the ones actually in use.

/// Get the uses's decrypted encryption key. Note: It's very important
/// to keep this key safe, as it can be used to decrypt all of the user's data
pub async fn get_user_encryption_key(&self) -> Result<String, MobileCryptoError> {
Expand Down Expand Up @@ -86,21 +108,6 @@
) -> Result<String, DeriveKeyConnectorError> {
derive_key_connector(request)
}

/// Generates a new key pair and encrypts the private key with the provided user key.
pub fn make_key_pair(&self, user_key: String) -> Result<MakeKeyPairResponse, CryptoError> {
make_key_pair(user_key)
}

/// Verifies a user's asymmetric keys by decrypting the private key with the provided user
/// key. Returns if the private key is decryptable and if it is a valid matching key.
/// Crypto initialization not required.
pub fn verify_asymmetric_keys(
&self,
request: VerifyAsymmetricKeysRequest,
) -> Result<VerifyAsymmetricKeysResponse, CryptoError> {
verify_asymmetric_keys(request)
}
}

impl Client {
Expand Down
6 changes: 3 additions & 3 deletions crates/bitwarden-wasm-internal/src/client.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
extern crate console_error_panic_hook;
use std::fmt::Display;

use bitwarden_core::{Client, ClientSettings};
use bitwarden_core::{mobile::CryptoClient, Client, ClientSettings};
use bitwarden_error::bitwarden_error;
use bitwarden_exporters::ExporterClientExt;
use bitwarden_vault::VaultClientExt;
use wasm_bindgen::prelude::*;

use crate::{CryptoClient, GeneratorClient, VaultClient};
use crate::{GeneratorClient, VaultClient};

#[wasm_bindgen]
pub struct BitwardenClient(pub(crate) Client);
Expand Down Expand Up @@ -41,7 +41,7 @@
}

pub fn crypto(&self) -> CryptoClient {
CryptoClient::new(self.0.crypto())
self.0.crypto()

Check warning on line 44 in crates/bitwarden-wasm-internal/src/client.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-wasm-internal/src/client.rs#L44

Added line #L44 was not covered by tests
}

pub fn vault(&self) -> VaultClient {
Expand Down
55 changes: 0 additions & 55 deletions crates/bitwarden-wasm-internal/src/crypto.rs

This file was deleted.

2 changes: 0 additions & 2 deletions crates/bitwarden-wasm-internal/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#![doc = include_str!("../README.md")]

mod client;
mod crypto;
mod custom_types;
mod generators;
mod init;
Expand All @@ -11,7 +10,6 @@ mod vault;

pub use bitwarden_ipc::wasm::*;
pub use client::BitwardenClient;
pub use crypto::CryptoClient;
pub use generators::GeneratorClient;
pub use init::init_sdk;
pub use vault::{folders::FoldersClient, VaultClient};
Loading