Skip to content

Commit

Permalink
Merge branch 'master' into ps/more-aes-decrypt-support
Browse files Browse the repository at this point in the history
# Conflicts:
#	crates/bitwarden/src/crypto/aes_ops.rs
#	crates/bitwarden/src/crypto/enc_string.rs
#	crates/bitwarden/src/crypto/master_key.rs
#	crates/bitwarden/src/crypto/rsa.rs
  • Loading branch information
dani-garcia committed Nov 23, 2023
2 parents 70a738e + 24f0dfd commit 4702fc1
Show file tree
Hide file tree
Showing 36 changed files with 1,464 additions and 674 deletions.
366 changes: 186 additions & 180 deletions Cargo.lock

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ codegen-units = 1
# This is fine as long as we don't have any unhandled panics, but let's keep it disabled for now
# strip = true

# Using master until 0.25.1 is released to fix https://github.com/mozilla/uniffi-rs/issues/1798
# Using git dependency temporarily to add support for immutable records in generated code
[patch.crates-io]
uniffi = { git = "https://github.com/mozilla/uniffi-rs", rev = "b369e7c15b1b7ebca34de9028209db11b7ff353d" }
uniffi_build = { git = "https://github.com/mozilla/uniffi-rs", rev = "b369e7c15b1b7ebca34de9028209db11b7ff353d" }
uniffi_bindgen = { git = "https://github.com/mozilla/uniffi-rs", rev = "b369e7c15b1b7ebca34de9028209db11b7ff353d" }
uniffi_core = { git = "https://github.com/mozilla/uniffi-rs", rev = "b369e7c15b1b7ebca34de9028209db11b7ff353d" }
uniffi_macros = { git = "https://github.com/mozilla/uniffi-rs", rev = "b369e7c15b1b7ebca34de9028209db11b7ff353d" }
uniffi = { git = "https://github.com/mozilla/uniffi-rs", rev = "0a03b713306d6ce3de033157fc2ce92a238c2e24" }
uniffi_build = { git = "https://github.com/mozilla/uniffi-rs", rev = "0a03b713306d6ce3de033157fc2ce92a238c2e24" }
uniffi_bindgen = { git = "https://github.com/mozilla/uniffi-rs", rev = "0a03b713306d6ce3de033157fc2ce92a238c2e24" }
uniffi_core = { git = "https://github.com/mozilla/uniffi-rs", rev = "0a03b713306d6ce3de033157fc2ce92a238c2e24" }
uniffi_macros = { git = "https://github.com/mozilla/uniffi-rs", rev = "0a03b713306d6ce3de033157fc2ce92a238c2e24" }
6 changes: 3 additions & 3 deletions crates/bitwarden-napi/package-lock.json

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

1 change: 0 additions & 1 deletion crates/bitwarden-napi/src/client.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
extern crate log;

use bitwarden_json::client::Client as JsonClient;
use napi::bindgen_prelude::*;
use napi_derive::napi;

#[napi]
Expand Down
8 changes: 4 additions & 4 deletions crates/bitwarden-py/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ name = "bitwarden_py"
crate-type = ["cdylib"]

[dependencies]
pyo3 = { version = "0.19.1", features = ["extension-module"] }
pyo3-log = "0.8.3"
pyo3 = { version = "0.20.0", features = ["extension-module"] }
pyo3-log = "0.9.0"

bitwarden-json = { path = "../bitwarden-json", features = ["secrets"] }

[build-dependencies]
pyo3-build-config = { version = "0.19.1" }
pyo3-build-config = { version = "0.20.0" }

[target.'cfg(not(target_arch="wasm32"))'.dependencies]
tokio = { version = "1.28.2", features = ["rt-multi-thread", "macros"] }
pyo3-asyncio = { version = "0.19.0", features = [
pyo3-asyncio = { version = "0.20.0", features = [
"attributes",
"tokio-runtime",
] }
4 changes: 2 additions & 2 deletions crates/bitwarden-uniffi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ chrono = { version = ">=0.4.26, <0.5", features = [
"std",
], default-features = false }
env_logger = "0.10.0"
uniffi = "=0.25.0"
uniffi = "=0.25.1"
schemars = { version = ">=0.8, <0.9", optional = true }

bitwarden = { path = "../bitwarden", features = ["mobile", "internal"] }

[build-dependencies]
uniffi = { version = "=0.25.0", features = ["build"] }
uniffi = { version = "=0.25.1", features = ["build"] }

[target.'cfg(any(target_os = "android", target_os = "ios"))'.dependencies]
openssl = { version = "0.10", features = ["vendored"] }
1 change: 1 addition & 0 deletions crates/bitwarden-uniffi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
```bash
cargo +nightly rustdoc -p bitwarden -- -Zunstable-options --output-format json
cargo +nightly rustdoc -p bitwarden-uniffi -- -Zunstable-options --output-format json
npm run schemas

npx ts-node ./support/docs/docs.ts > languages/kotlin/doc.md
```
48 changes: 48 additions & 0 deletions crates/bitwarden-uniffi/src/crypto.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use std::sync::Arc;

use bitwarden::mobile::crypto::{InitOrgCryptoRequest, InitUserCryptoRequest};

use crate::{error::Result, Client};

#[derive(uniffi::Object)]
pub struct ClientCrypto(pub(crate) Arc<Client>);

#[uniffi::export]
impl ClientCrypto {
/// Initialization method for the user crypto. Needs to be called before any other crypto operations.
pub async fn initialize_user_crypto(&self, req: InitUserCryptoRequest) -> Result<()> {
Ok(self
.0
.0
.write()
.await
.crypto()
.initialize_user_crypto(req)
.await?)
}

/// Initialization method for the organization crypto. Needs to be called after `initialize_user_crypto` but before any other crypto operations.
pub async fn initialize_org_crypto(&self, req: InitOrgCryptoRequest) -> Result<()> {
Ok(self
.0
.0
.write()
.await
.crypto()
.initialize_org_crypto(req)
.await?)
}

/// 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> {
Ok(self
.0
.0
.write()
.await
.crypto()
.get_user_encryption_key()
.await?)
}
}
5 changes: 3 additions & 2 deletions crates/bitwarden-uniffi/src/docs.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bitwarden::{
auth::password::MasterPasswordPolicyOptions,
client::kdf::Kdf,
mobile::crypto::InitCryptoRequest,
mobile::crypto::{InitOrgCryptoRequest, InitUserCryptoRequest},
tool::{ExportFormat, PassphraseGeneratorRequest, PasswordGeneratorRequest},
vault::{
Cipher, CipherView, Collection, Folder, FolderView, Send, SendListView, SendView,
Expand All @@ -24,7 +24,8 @@ pub enum DocRef {
SendListView(SendListView),

// Crypto
InitCryptoRequest(InitCryptoRequest),
InitUserCryptoRequest(InitUserCryptoRequest),
InitOrgCryptoRequest(InitOrgCryptoRequest),

// Generators
PasswordGeneratorRequest(PasswordGeneratorRequest),
Expand Down
22 changes: 3 additions & 19 deletions crates/bitwarden-uniffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ use std::sync::Arc;

use async_lock::RwLock;
use auth::ClientAuth;
use bitwarden::{client::client_settings::ClientSettings, mobile::crypto::InitCryptoRequest};
use bitwarden::client::client_settings::ClientSettings;

pub mod auth;
pub mod crypto;
mod error;
pub mod tool;
mod uniffi_support;
Expand All @@ -15,16 +16,14 @@ pub mod vault;
#[cfg(feature = "docs")]
pub mod docs;

use crypto::ClientCrypto;
use error::Result;
use tool::ClientGenerators;
use vault::ClientVault;

#[derive(uniffi::Object)]
pub struct Client(RwLock<bitwarden::Client>);

#[derive(uniffi::Object)]
pub struct ClientCrypto(Arc<Client>);

#[uniffi::export]
impl Client {
/// Initialize a new instance of the SDK client
Expand Down Expand Up @@ -58,18 +57,3 @@ impl Client {
msg
}
}

#[uniffi::export]
impl ClientCrypto {
/// Initialization method for the crypto. Needs to be called before any other crypto operations.
pub async fn initialize_crypto(&self, req: InitCryptoRequest) -> Result<()> {
Ok(self
.0
.0
.write()
.await
.crypto()
.initialize_crypto(req)
.await?)
}
}
2 changes: 2 additions & 0 deletions crates/bitwarden-uniffi/uniffi.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
[bindings.kotlin]
package_name = "com.bitwarden.sdk"
cdylib_name = "bitwarden_uniffi"
generate_immutable_records = true

[bindings.swift]
ffi_module_name = "BitwardenFFI"
module_name = "BitwardenSDK"
generate_immutable_records = true
2 changes: 1 addition & 1 deletion crates/bitwarden-wasm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ crate-type = ["cdylib", "rlib"]
[dependencies]
js-sys = "0.3.63"
serde = {version = "1.0.163", features = ["derive"] }
wasm-bindgen = { version = "0.2.86", features = ["serde-serialize"] }
wasm-bindgen = { version = "=0.2.87", features = ["serde-serialize"] }
wasm-bindgen-futures = "0.4.36"
console_error_panic_hook = "0.1.7"
console_log = { version = "1.0.0", features = ["color"] }
Expand Down
2 changes: 1 addition & 1 deletion crates/bitwarden/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ chrono = { version = ">=0.4.26, <0.5", features = [
"serde",
"std",
], default-features = false }
uniffi = { version = "=0.25.0", optional = true }
uniffi = { version = "=0.25.1", optional = true }

# We don't use this directly (it's used by rand), but we need it here to enable WASM support
getrandom = { version = ">=0.2.9", features = ["js"] }
Expand Down
17 changes: 17 additions & 0 deletions crates/bitwarden/src/client/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,23 @@ impl Client {
Ok(self.encryption_settings.as_ref().unwrap())
}

#[cfg(feature = "mobile")]
pub(crate) fn initialize_user_crypto_decrypted_key(
&mut self,
decrypted_user_key: &str,
private_key: EncString,
) -> Result<&EncryptionSettings> {
let user_key = decrypted_user_key.parse::<SymmetricCryptoKey>()?;
self.encryption_settings = Some(EncryptionSettings::new_decrypted_key(
user_key,
private_key,
)?);
Ok(self
.encryption_settings
.as_ref()
.expect("It was initialized on the previous line"))
}

pub(crate) fn initialize_crypto_single_key(
&mut self,
key: SymmetricCryptoKey,
Expand Down
42 changes: 28 additions & 14 deletions crates/bitwarden/src/client/encryption_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ impl std::fmt::Debug for EncryptionSettings {
}

impl EncryptionSettings {
/// Initialize the encryption settings with the user password and their encrypted keys
#[cfg(feature = "internal")]
pub(crate) fn new(
login_method: &UserLoginMethod,
Expand All @@ -45,24 +46,33 @@ impl EncryptionSettings {
// Decrypt the user key
let user_key = master_key.decrypt_user_key(user_key)?;

// Decrypt the private key with the user key
let private_key = {
let dec: Vec<u8> = private_key.decrypt_with_key(&user_key)?;
Some(
rsa::RsaPrivateKey::from_pkcs8_der(&dec)
.map_err(|_| CryptoError::InvalidKey)?,
)
};

Ok(EncryptionSettings {
user_key,
private_key,
org_keys: HashMap::new(),
})
Self::new_decrypted_key(user_key, private_key)
}
}
}

/// Initialize the encryption settings with the decrypted user key and the encrypted user private key
/// This should only be used when unlocking the vault via biometrics or when the vault is set to lock: "never"
/// Otherwise handling the decrypted user key is dangerous and discouraged
#[cfg(feature = "internal")]
pub(crate) fn new_decrypted_key(
user_key: SymmetricCryptoKey,
private_key: EncString,
) -> Result<Self> {
let private_key = {
let dec: Vec<u8> = private_key.decrypt_with_key(&user_key)?;
Some(rsa::RsaPrivateKey::from_pkcs8_der(&dec).map_err(|_| CryptoError::InvalidKey)?)
};

Ok(EncryptionSettings {
user_key,
private_key,
org_keys: HashMap::new(),
})
}

/// Initialize the encryption settings with only a single decrypted key.
/// This is used only for logging in Secrets Manager with an access token
pub(crate) fn new_single_key(key: SymmetricCryptoKey) -> Self {
EncryptionSettings {
user_key: key,
Expand All @@ -80,6 +90,10 @@ impl EncryptionSettings {

let private_key = self.private_key.as_ref().ok_or(Error::VaultLocked)?;

// Make sure we only keep the keys given in the arguments and not any of the previous
// ones, which might be from organizations that the user is no longer a part of anymore
self.org_keys.clear();

// Decrypt the org keys with the private key
for (org_id, org_enc_key) in org_enc_keys {
let data = match org_enc_key {
Expand Down
Loading

0 comments on commit 4702fc1

Please sign in to comment.