diff --git a/README.md b/README.md
index a1ef88b7d..6c639d052 100644
--- a/README.md
+++ b/README.md
@@ -140,5 +140,24 @@ VALUES
);
```
+## Developer tools
+
+This project recommends the use of certain developer tools, and also includes configurations for
+them to make developers lives easier. The use of these tools is optional and they might require a
+separate installation step.
+
+The list of developer tools is:
+
+- `Visual Studio Code`: We provide a recommended extension list which should show under the
+ `Extensions` tab when opening this project with the editor. We also offer a few launch settings
+ and tasks to build and run the SDK
+- `bacon`: This is a CLI background code checker. We provide a configuration file with some of the
+ most common tasks to run (`check`, `clippy`, `test`, `doc` - run `bacon -l` to see them all). This
+ tool needs to be installed separately by running `cargo install bacon --locked`.
+- `nexttest`: This is a new and faster test runner, capable of running tests in parallel and with a
+ much nicer output compared to `cargo test`. This tool needs to be installed separately by running
+ `cargo install cargo-nextest --locked`. It can be manually run using
+ `cargo nextest run --all-features`
+
[secrets-manager]: https://bitwarden.com/products/secrets-manager/
[bws-help]: https://bitwarden.com/help/secrets-manager-cli/
diff --git a/bacon.toml b/bacon.toml
new file mode 100644
index 000000000..6844980d5
--- /dev/null
+++ b/bacon.toml
@@ -0,0 +1,78 @@
+# This is a configuration file for the bacon tool
+#
+# Bacon repository: https://github.com/Canop/bacon
+# Complete help on configuration: https://dystroy.org/bacon/config/
+# You can also check bacon's own bacon.toml file
+# as an example: https://github.com/Canop/bacon/blob/main/bacon.toml
+
+default_job = "check"
+
+[jobs.check]
+command = ["cargo", "check", "--color", "always"]
+need_stdout = false
+
+[jobs.check-all]
+command = ["cargo", "check", "--all-targets", "--color", "always"]
+need_stdout = false
+
+[jobs.clippy]
+command = ["cargo", "clippy", "--all-targets", "--color", "always"]
+need_stdout = false
+
+[jobs.test]
+command = [
+ "cargo",
+ "test",
+ "--all-features",
+ "--color",
+ "always",
+ "--",
+ "--color",
+ "always", # see https://github.com/Canop/bacon/issues/124
+]
+need_stdout = true
+
+[jobs.doc]
+command = ["cargo", "doc", "--color", "always", "--no-deps"]
+need_stdout = false
+
+# If the doc compiles, then it opens in your browser and bacon switches
+# to the previous job
+[jobs.doc-open]
+command = ["cargo", "doc", "--color", "always", "--no-deps", "--open"]
+need_stdout = false
+on_success = "back" # so that we don't open the browser at each change
+
+[jobs.doc-internal]
+command = [
+ "cargo",
+ "doc",
+ "--color",
+ "always",
+ "--no-deps",
+ "--all-features",
+ "--document-private-items",
+]
+need_stdout = false
+
+[jobs.doc-internal-open]
+command = [
+ "cargo",
+ "doc",
+ "--color",
+ "always",
+ "--no-deps",
+ "--all-features",
+ "--document-private-items",
+ "--open",
+]
+allow_warnings = true
+need_stdout = false
+on_success = "job:doc-internal"
+
+# You may define here keybindings that would be specific to
+# a project, for example a shortcut to launch a specific job.
+# Shortcuts to internal functions (scrolling, toggling, etc.)
+# should go in your personal global prefs.toml file instead.
+[keybindings]
+# alt-m = "job:my-job"
diff --git a/crates/bitwarden-crypto/src/keys/master_key.rs b/crates/bitwarden-crypto/src/keys/master_key.rs
index 1fd678452..b3a20fbc4 100644
--- a/crates/bitwarden-crypto/src/keys/master_key.rs
+++ b/crates/bitwarden-crypto/src/keys/master_key.rs
@@ -7,6 +7,10 @@ use serde::{Deserialize, Serialize};
use super::utils::{derive_kdf_key, stretch_kdf_key};
use crate::{util, CryptoError, EncString, KeyDecryptable, Result, SymmetricCryptoKey, UserKey};
+/// Key Derivation Function for Bitwarden Account
+///
+/// In Bitwarden accounts can use multiple KDFs to derive their master key from their password. This
+/// Enum represents all the possible KDFs.
#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[cfg_attr(feature = "mobile", derive(uniffi::Enum))]
@@ -22,6 +26,7 @@ pub enum Kdf {
}
impl Default for Kdf {
+ /// Default KDF for new accounts.
fn default() -> Self {
Kdf::PBKDF2 {
iterations: default_pbkdf2_iterations(),
@@ -29,15 +34,19 @@ impl Default for Kdf {
}
}
+/// Default PBKDF2 iterations
pub fn default_pbkdf2_iterations() -> NonZeroU32 {
NonZeroU32::new(600_000).expect("Non-zero number")
}
+/// Default Argon2 iterations
pub fn default_argon2_iterations() -> NonZeroU32 {
NonZeroU32::new(3).expect("Non-zero number")
}
+/// Default Argon2 memory
pub fn default_argon2_memory() -> NonZeroU32 {
NonZeroU32::new(64).expect("Non-zero number")
}
+/// Default Argon2 parallelism
pub fn default_argon2_parallelism() -> NonZeroU32 {
NonZeroU32::new(4).expect("Non-zero number")
}
diff --git a/crates/bitwarden-crypto/src/lib.rs b/crates/bitwarden-crypto/src/lib.rs
index 8c368580a..babcc921d 100644
--- a/crates/bitwarden-crypto/src/lib.rs
+++ b/crates/bitwarden-crypto/src/lib.rs
@@ -1,15 +1,47 @@
//! # Bitwarden Cryptographic primitives
//!
-//! This crate contains the cryptographic primitives used throughout the SDK. The crate makes a
-//! best effort to abstract away cryptographic concepts into concepts such as [`EncString`],
-//! [`AsymmetricEncString`] and [`SymmetricCryptoKey`].
+//! This crate contains the cryptographic primitives used throughout the SDK. The general
+//! aspiration is for this crate to handle all the difficult cryptographic operations and expose
+//! higher level concepts to the rest of the SDK.
//!
-//! ## Conventions:
+//!
+//! Generally you should not find yourself needing to edit this crate! Everything written
+//! here requires additional care and attention to ensure that the cryptographic primitives are
+//! secure.
+//!
+//! ## Example:
+//!
+//! ```rust
+//! use bitwarden_crypto::{SymmetricCryptoKey, KeyEncryptable, KeyDecryptable, CryptoError};
+//!
+//! async fn example() -> Result<(), CryptoError> {
+//! let key = SymmetricCryptoKey::generate(rand::thread_rng());
+//!
+//! let data = "Hello, World!".to_owned();
+//! let encrypted = data.clone().encrypt_with_key(&key)?;
+//! let decrypted: String = encrypted.decrypt_with_key(&key)?;
+//!
+//! assert_eq!(data, decrypted);
+//! Ok(())
+//! }
+//! ```
+//!
+//! ## Development considerations
+//!
+//! This crate is expected to provide long term support for cryptographic operations. To that end,
+//! the following considerations should be taken into account when making changes to this crate:
+//!
+//! - Limit public interfaces to the bare minimum.
+//! - Breaking changes should be rare and well communicated.
+//! - Serializable representation of keys and encrypted data must be supported indefinitely as we
+//! have no way to update all data.
+//!
+//! ### Conventions:
//!
//! - Pure Functions that deterministically "derive" keys from input are prefixed with `derive_`.
//! - Functions that generate non deterministically keys are prefixed with `make_`.
//!
-//! ## Differences from `clients`
+//! ### Differences from `clients`
//!
//! There are some noteworthy differences compared to the other Bitwarden
//! [clients](https://github.com/bitwarden/clients). These changes are made in an effort to
diff --git a/crates/bitwarden-crypto/src/rsa.rs b/crates/bitwarden-crypto/src/rsa.rs
index 98f1282cc..6e3658c04 100644
--- a/crates/bitwarden-crypto/src/rsa.rs
+++ b/crates/bitwarden-crypto/src/rsa.rs
@@ -21,6 +21,7 @@ pub struct RsaKeyPair {
pub private: EncString,
}
+/// Generate a new RSA key pair of 2048 bits
pub(crate) fn make_key_pair(key: &SymmetricCryptoKey) -> Result {
let mut rng = rand::thread_rng();
let bits = 2048;
@@ -48,6 +49,7 @@ pub(crate) fn make_key_pair(key: &SymmetricCryptoKey) -> Result {
})
}
+/// Encrypt data using RSA-OAEP-SHA1 with a 2048 bit key
pub(super) fn encrypt_rsa2048_oaep_sha1(public_key: &RsaPublicKey, data: &[u8]) -> Result> {
let mut rng = rand::thread_rng();
diff --git a/crates/bitwarden-crypto/src/wordlist.rs b/crates/bitwarden-crypto/src/wordlist.rs
index 4cc30ff74..f1e7a59c0 100644
--- a/crates/bitwarden-crypto/src/wordlist.rs
+++ b/crates/bitwarden-crypto/src/wordlist.rs
@@ -1,4 +1,4 @@
-// EFF's Long Wordlist from https://www.eff.org/dice
+/// EFF's Long Wordlist from
pub const EFF_LONG_WORD_LIST: &[&str] = &[
"abacus",
"abdomen",
diff --git a/crates/bitwarden-exporters/src/csv.rs b/crates/bitwarden-exporters/src/csv.rs
index eb60fca21..a0dcd1040 100644
--- a/crates/bitwarden-exporters/src/csv.rs
+++ b/crates/bitwarden-exporters/src/csv.rs
@@ -54,7 +54,7 @@ pub(crate) fn export_csv(folders: Vec, ciphers: Vec) -> Result
///
/// Be careful when changing this struct to maintain compatibility with old exports.
#[derive(serde::Serialize)]
diff --git a/crates/bitwarden-generators/src/username.rs b/crates/bitwarden-generators/src/username.rs
index ccb46604b..36ded98b2 100644
--- a/crates/bitwarden-generators/src/username.rs
+++ b/crates/bitwarden-generators/src/username.rs
@@ -173,7 +173,7 @@ fn random_number(mut rng: impl RngCore) -> String {
}
/// Generate a username using a plus addressed email address
-/// The format is +@
+/// The format is `+@`
fn username_subaddress(mut rng: impl RngCore, r#type: AppendType, email: String) -> String {
if email.len() < 3 {
return email;
@@ -195,7 +195,7 @@ fn username_subaddress(mut rng: impl RngCore, r#type: AppendType, email: String)
}
/// Generate a username using a catchall email address
-/// The format is @
+/// The format is `@`
fn username_catchall(mut rng: impl RngCore, r#type: AppendType, domain: String) -> String {
if domain.is_empty() {
return domain;
diff --git a/crates/bitwarden-napi/Cargo.toml b/crates/bitwarden-napi/Cargo.toml
index 16853dbbf..7bcd54aad 100644
--- a/crates/bitwarden-napi/Cargo.toml
+++ b/crates/bitwarden-napi/Cargo.toml
@@ -29,8 +29,5 @@ napi-derive = "2"
[build-dependencies]
napi-build = "2.1.0"
-[profile.release]
-lto = true
-
[lints]
workspace = true
diff --git a/crates/bitwarden/src/auth/auth_request.rs b/crates/bitwarden/src/auth/auth_request.rs
index 04dc9fdce..68e2cad90 100644
--- a/crates/bitwarden/src/auth/auth_request.rs
+++ b/crates/bitwarden/src/auth/auth_request.rs
@@ -125,26 +125,25 @@ mod tests {
use bitwarden_crypto::Kdf;
use super::*;
- use crate::{
- client::{LoginMethod, UserLoginMethod},
- mobile::crypto::{AuthRequestMethod, InitUserCryptoMethod, InitUserCryptoRequest},
- };
+ use crate::mobile::crypto::{AuthRequestMethod, InitUserCryptoMethod, InitUserCryptoRequest};
#[test]
fn test_approve() {
let mut client = Client::new(None);
- client.set_login_method(LoginMethod::User(UserLoginMethod::Username {
- client_id: "7b821276-e27c-400b-9853-606393c87f18".to_owned(),
- email: "test@bitwarden.com".to_owned(),
- kdf: Kdf::PBKDF2 {
+
+ let master_key = bitwarden_crypto::MasterKey::derive(
+ "asdfasdfasdf".as_bytes(),
+ "test@bitwarden.com".as_bytes(),
+ &Kdf::PBKDF2 {
iterations: NonZeroU32::new(600_000).unwrap(),
},
- }));
+ )
+ .unwrap();
let user_key = "2.Q/2PhzcC7GdeiMHhWguYAQ==|GpqzVdr0go0ug5cZh1n+uixeBC3oC90CIe0hd/HWA/pTRDZ8ane4fmsEIcuc8eMKUt55Y2q/fbNzsYu41YTZzzsJUSeqVjT8/iTQtgnNdpo=|dwI+uyvZ1h/iZ03VQ+/wrGEFYVewBUUl/syYgjsNMbE=".parse().unwrap();
let private_key ="2.yN7l00BOlUE0Sb0M//Q53w==|EwKG/BduQRQ33Izqc/ogoBROIoI5dmgrxSo82sgzgAMIBt3A2FZ9vPRMY+GWT85JiqytDitGR3TqwnFUBhKUpRRAq4x7rA6A1arHrFp5Tp1p21O3SfjtvB3quiOKbqWk6ZaU1Np9HwqwAecddFcB0YyBEiRX3VwF2pgpAdiPbSMuvo2qIgyob0CUoC/h4Bz1be7Qa7B0Xw9/fMKkB1LpOm925lzqosyMQM62YpMGkjMsbZz0uPopu32fxzDWSPr+kekNNyLt9InGhTpxLmq1go/pXR2uw5dfpXc5yuta7DB0EGBwnQ8Vl5HPdDooqOTD9I1jE0mRyuBpWTTI3FRnu3JUh3rIyGBJhUmHqGZvw2CKdqHCIrQeQkkEYqOeJRJVdBjhv5KGJifqT3BFRwX/YFJIChAQpebNQKXe/0kPivWokHWwXlDB7S7mBZzhaAPidZvnuIhalE2qmTypDwHy22FyqV58T8MGGMchcASDi/QXI6kcdpJzPXSeU9o+NC68QDlOIrMVxKFeE7w7PvVmAaxEo0YwmuAzzKy9QpdlK0aab/xEi8V4iXj4hGepqAvHkXIQd+r3FNeiLfllkb61p6WTjr5urcmDQMR94/wYoilpG5OlybHdbhsYHvIzYoLrC7fzl630gcO6t4nM24vdB6Ymg9BVpEgKRAxSbE62Tqacxqnz9AcmgItb48NiR/He3n3ydGjPYuKk/ihZMgEwAEZvSlNxYONSbYrIGDtOY+8Nbt6KiH3l06wjZW8tcmFeVlWv+tWotnTY9IqlAfvNVTjtsobqtQnvsiDjdEVtNy/s2ci5TH+NdZluca2OVEr91Wayxh70kpM6ib4UGbfdmGgCo74gtKvKSJU0rTHakQ5L9JlaSDD5FamBRyI0qfL43Ad9qOUZ8DaffDCyuaVyuqk7cz9HwmEmvWU3VQ+5t06n/5kRDXttcw8w+3qClEEdGo1KeENcnXCB32dQe3tDTFpuAIMLqwXs6FhpawfZ5kPYvLPczGWaqftIs/RXJ/EltGc0ugw2dmTLpoQhCqrcKEBDoYVk0LDZKsnzitOGdi9mOWse7Se8798ib1UsHFUjGzISEt6upestxOeupSTOh0v4+AjXbDzRUyogHww3V+Bqg71bkcMxtB+WM+pn1XNbVTyl9NR040nhP7KEf6e9ruXAtmrBC2ah5cFEpLIot77VFZ9ilLuitSz+7T8n1yAh1IEG6xxXxninAZIzi2qGbH69O5RSpOJuJTv17zTLJQIIc781JwQ2TTwTGnx5wZLbffhCasowJKd2EVcyMJyhz6ru0PvXWJ4hUdkARJs3Xu8dus9a86N8Xk6aAPzBDqzYb1vyFIfBxP0oO8xFHgd30Cgmz8UrSE3qeWRrF8ftrI6xQnFjHBGWD/JWSvd6YMcQED0aVuQkuNW9ST/DzQThPzRfPUoiL10yAmV7Ytu4fR3x2sF0Yfi87YhHFuCMpV/DsqxmUizyiJuD938eRcH8hzR/VO53Qo3UIsqOLcyXtTv6THjSlTopQ+JOLOnHm1w8dzYbLN44OG44rRsbihMUQp+wUZ6bsI8rrOnm9WErzkbQFbrfAINdoCiNa6cimYIjvvnMTaFWNymqY1vZxGztQiMiHiHYwTfwHTXrb9j0uPM=|09J28iXv9oWzYtzK2LBT6Yht4IT4MijEkk0fwFdrVQ4=".parse().unwrap();
client
- .initialize_user_crypto("asdfasdfasdf", user_key, private_key)
+ .initialize_user_crypto_master_key(master_key, user_key, private_key)
.unwrap();
let public_key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvyLRDUwXB4BfQ507D4meFPmwn5zwy3IqTPJO4plrrhnclWahXa240BzyFW9gHgYu+Jrgms5xBfRTBMcEsqqNm7+JpB6C1B6yvnik0DpJgWQw1rwvy4SUYidpR/AWbQi47n/hvnmzI/sQxGddVfvWu1iTKOlf5blbKYAXnUE5DZBGnrWfacNXwRRdtP06tFB0LwDgw+91CeLSJ9py6dm1qX5JIxoO8StJOQl65goLCdrTWlox+0Jh4xFUfCkb+s3px+OhSCzJbvG/hlrSRcUz5GnwlCEyF3v5lfUtV96MJD+78d8pmH6CfFAp2wxKRAbGdk+JccJYO6y6oIXd3Fm7twIDAQAB";
@@ -206,14 +205,13 @@ mod tests {
// Initialize an existing client which is unlocked
let mut existing_device = Client::new(None);
- existing_device.set_login_method(LoginMethod::User(UserLoginMethod::Username {
- client_id: "123".to_owned(),
- email: email.to_owned(),
- kdf: kdf.clone(),
- }));
+
+ let master_key =
+ bitwarden_crypto::MasterKey::derive("asdfasdfasdf".as_bytes(), email.as_bytes(), &kdf)
+ .unwrap();
existing_device
- .initialize_user_crypto("asdfasdfasdf", user_key, private_key.parse().unwrap())
+ .initialize_user_crypto_master_key(master_key, user_key, private_key.parse().unwrap())
.unwrap();
// Initialize a new device which will request to be logged in
diff --git a/crates/bitwarden/src/auth/login/api_key.rs b/crates/bitwarden/src/auth/login/api_key.rs
index 5d7fdcd96..8b83e3a38 100644
--- a/crates/bitwarden/src/auth/login/api_key.rs
+++ b/crates/bitwarden/src/auth/login/api_key.rs
@@ -1,4 +1,4 @@
-use bitwarden_crypto::EncString;
+use bitwarden_crypto::{EncString, MasterKey};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
@@ -37,6 +37,9 @@ pub(crate) async fn login_api_key(
r.refresh_token.clone(),
r.expires_in,
);
+
+ let master_key = MasterKey::derive(input.password.as_bytes(), email.as_bytes(), &kdf)?;
+
client.set_login_method(LoginMethod::User(UserLoginMethod::ApiKey {
client_id: input.client_id.to_owned(),
client_secret: input.client_secret.to_owned(),
@@ -47,7 +50,7 @@ pub(crate) async fn login_api_key(
let user_key: EncString = require!(r.key.as_deref()).parse()?;
let private_key: EncString = require!(r.private_key.as_deref()).parse()?;
- client.initialize_user_crypto(&input.password, user_key, private_key)?;
+ client.initialize_user_crypto_master_key(master_key, user_key, private_key)?;
}
ApiKeyLoginResponse::process_response(response)
diff --git a/crates/bitwarden/src/auth/login/password.rs b/crates/bitwarden/src/auth/login/password.rs
index 8ae9daebc..e0cb67dbe 100644
--- a/crates/bitwarden/src/auth/login/password.rs
+++ b/crates/bitwarden/src/auth/login/password.rs
@@ -1,5 +1,5 @@
#[cfg(feature = "internal")]
-use log::{debug, info};
+use log::info;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
@@ -22,19 +22,20 @@ pub(crate) async fn login_password(
client: &mut Client,
input: &PasswordLoginRequest,
) -> Result {
- use bitwarden_crypto::{EncString, HashPurpose};
+ use bitwarden_crypto::{EncString, HashPurpose, MasterKey};
- use crate::{auth::determine_password_hash, client::UserLoginMethod, error::require};
+ use crate::{client::UserLoginMethod, error::require};
info!("password logging in");
- debug!("{:#?}, {:#?}", client, input);
- let password_hash = determine_password_hash(
- &input.email,
+ let master_key = MasterKey::derive(
+ input.password.as_bytes(),
+ input.email.as_bytes(),
&input.kdf,
- &input.password,
- HashPurpose::ServerAuthorization,
)?;
+ let password_hash = master_key
+ .derive_master_key_hash(input.password.as_bytes(), HashPurpose::ServerAuthorization)?;
+
let response = request_identity_tokens(client, input, &password_hash).await?;
if let IdentityTokenResponse::Authenticated(r) = &response {
@@ -52,7 +53,7 @@ pub(crate) async fn login_password(
let user_key: EncString = require!(r.key.as_deref()).parse()?;
let private_key: EncString = require!(r.private_key.as_deref()).parse()?;
- client.initialize_user_crypto(&input.password, user_key, private_key)?;
+ client.initialize_user_crypto_master_key(master_key, user_key, private_key)?;
}
PasswordLoginResponse::process_response(response)
diff --git a/crates/bitwarden/src/auth/password/validate.rs b/crates/bitwarden/src/auth/password/validate.rs
index 9003347d9..7e30d858b 100644
--- a/crates/bitwarden/src/auth/password/validate.rs
+++ b/crates/bitwarden/src/auth/password/validate.rs
@@ -111,19 +111,28 @@ mod tests {
use crate::client::{Client, Kdf, LoginMethod, UserLoginMethod};
let mut client = Client::new(None);
+
+ let password = "asdfasdfasdf";
+ let email = "test@bitwarden.com";
+ let kdf = Kdf::PBKDF2 {
+ iterations: NonZeroU32::new(600_000).unwrap(),
+ };
+
client.set_login_method(LoginMethod::User(UserLoginMethod::Username {
- email: "test@bitwarden.com".to_string(),
- kdf: Kdf::PBKDF2 {
- iterations: NonZeroU32::new(600_000).unwrap(),
- },
+ email: email.to_string(),
+ kdf: kdf.clone(),
client_id: "1".to_string(),
}));
+ let master_key =
+ bitwarden_crypto::MasterKey::derive(password.as_bytes(), email.as_bytes(), &kdf)
+ .unwrap();
+
let user_key = "2.Q/2PhzcC7GdeiMHhWguYAQ==|GpqzVdr0go0ug5cZh1n+uixeBC3oC90CIe0hd/HWA/pTRDZ8ane4fmsEIcuc8eMKUt55Y2q/fbNzsYu41YTZzzsJUSeqVjT8/iTQtgnNdpo=|dwI+uyvZ1h/iZ03VQ+/wrGEFYVewBUUl/syYgjsNMbE=";
let private_key = "2.yN7l00BOlUE0Sb0M//Q53w==|EwKG/BduQRQ33Izqc/ogoBROIoI5dmgrxSo82sgzgAMIBt3A2FZ9vPRMY+GWT85JiqytDitGR3TqwnFUBhKUpRRAq4x7rA6A1arHrFp5Tp1p21O3SfjtvB3quiOKbqWk6ZaU1Np9HwqwAecddFcB0YyBEiRX3VwF2pgpAdiPbSMuvo2qIgyob0CUoC/h4Bz1be7Qa7B0Xw9/fMKkB1LpOm925lzqosyMQM62YpMGkjMsbZz0uPopu32fxzDWSPr+kekNNyLt9InGhTpxLmq1go/pXR2uw5dfpXc5yuta7DB0EGBwnQ8Vl5HPdDooqOTD9I1jE0mRyuBpWTTI3FRnu3JUh3rIyGBJhUmHqGZvw2CKdqHCIrQeQkkEYqOeJRJVdBjhv5KGJifqT3BFRwX/YFJIChAQpebNQKXe/0kPivWokHWwXlDB7S7mBZzhaAPidZvnuIhalE2qmTypDwHy22FyqV58T8MGGMchcASDi/QXI6kcdpJzPXSeU9o+NC68QDlOIrMVxKFeE7w7PvVmAaxEo0YwmuAzzKy9QpdlK0aab/xEi8V4iXj4hGepqAvHkXIQd+r3FNeiLfllkb61p6WTjr5urcmDQMR94/wYoilpG5OlybHdbhsYHvIzYoLrC7fzl630gcO6t4nM24vdB6Ymg9BVpEgKRAxSbE62Tqacxqnz9AcmgItb48NiR/He3n3ydGjPYuKk/ihZMgEwAEZvSlNxYONSbYrIGDtOY+8Nbt6KiH3l06wjZW8tcmFeVlWv+tWotnTY9IqlAfvNVTjtsobqtQnvsiDjdEVtNy/s2ci5TH+NdZluca2OVEr91Wayxh70kpM6ib4UGbfdmGgCo74gtKvKSJU0rTHakQ5L9JlaSDD5FamBRyI0qfL43Ad9qOUZ8DaffDCyuaVyuqk7cz9HwmEmvWU3VQ+5t06n/5kRDXttcw8w+3qClEEdGo1KeENcnXCB32dQe3tDTFpuAIMLqwXs6FhpawfZ5kPYvLPczGWaqftIs/RXJ/EltGc0ugw2dmTLpoQhCqrcKEBDoYVk0LDZKsnzitOGdi9mOWse7Se8798ib1UsHFUjGzISEt6upestxOeupSTOh0v4+AjXbDzRUyogHww3V+Bqg71bkcMxtB+WM+pn1XNbVTyl9NR040nhP7KEf6e9ruXAtmrBC2ah5cFEpLIot77VFZ9ilLuitSz+7T8n1yAh1IEG6xxXxninAZIzi2qGbH69O5RSpOJuJTv17zTLJQIIc781JwQ2TTwTGnx5wZLbffhCasowJKd2EVcyMJyhz6ru0PvXWJ4hUdkARJs3Xu8dus9a86N8Xk6aAPzBDqzYb1vyFIfBxP0oO8xFHgd30Cgmz8UrSE3qeWRrF8ftrI6xQnFjHBGWD/JWSvd6YMcQED0aVuQkuNW9ST/DzQThPzRfPUoiL10yAmV7Ytu4fR3x2sF0Yfi87YhHFuCMpV/DsqxmUizyiJuD938eRcH8hzR/VO53Qo3UIsqOLcyXtTv6THjSlTopQ+JOLOnHm1w8dzYbLN44OG44rRsbihMUQp+wUZ6bsI8rrOnm9WErzkbQFbrfAINdoCiNa6cimYIjvvnMTaFWNymqY1vZxGztQiMiHiHYwTfwHTXrb9j0uPM=|09J28iXv9oWzYtzK2LBT6Yht4IT4MijEkk0fwFdrVQ4=".parse().unwrap();
client
- .initialize_user_crypto("asdfasdfasdf", user_key.parse().unwrap(), private_key)
+ .initialize_user_crypto_master_key(master_key, user_key.parse().unwrap(), private_key)
.unwrap();
let result =
@@ -142,19 +151,28 @@ mod tests {
use crate::client::{Client, Kdf, LoginMethod, UserLoginMethod};
let mut client = Client::new(None);
+
+ let password = "asdfasdfasdf";
+ let email = "test@bitwarden.com";
+ let kdf = Kdf::PBKDF2 {
+ iterations: NonZeroU32::new(600_000).unwrap(),
+ };
+
client.set_login_method(LoginMethod::User(UserLoginMethod::Username {
- email: "test@bitwarden.com".to_string(),
- kdf: Kdf::PBKDF2 {
- iterations: NonZeroU32::new(600_000).unwrap(),
- },
+ email: email.to_string(),
+ kdf: kdf.clone(),
client_id: "1".to_string(),
}));
+ let master_key =
+ bitwarden_crypto::MasterKey::derive(password.as_bytes(), email.as_bytes(), &kdf)
+ .unwrap();
+
let user_key = "2.Q/2PhzcC7GdeiMHhWguYAQ==|GpqzVdr0go0ug5cZh1n+uixeBC3oC90CIe0hd/HWA/pTRDZ8ane4fmsEIcuc8eMKUt55Y2q/fbNzsYu41YTZzzsJUSeqVjT8/iTQtgnNdpo=|dwI+uyvZ1h/iZ03VQ+/wrGEFYVewBUUl/syYgjsNMbE=";
let private_key = "2.yN7l00BOlUE0Sb0M//Q53w==|EwKG/BduQRQ33Izqc/ogoBROIoI5dmgrxSo82sgzgAMIBt3A2FZ9vPRMY+GWT85JiqytDitGR3TqwnFUBhKUpRRAq4x7rA6A1arHrFp5Tp1p21O3SfjtvB3quiOKbqWk6ZaU1Np9HwqwAecddFcB0YyBEiRX3VwF2pgpAdiPbSMuvo2qIgyob0CUoC/h4Bz1be7Qa7B0Xw9/fMKkB1LpOm925lzqosyMQM62YpMGkjMsbZz0uPopu32fxzDWSPr+kekNNyLt9InGhTpxLmq1go/pXR2uw5dfpXc5yuta7DB0EGBwnQ8Vl5HPdDooqOTD9I1jE0mRyuBpWTTI3FRnu3JUh3rIyGBJhUmHqGZvw2CKdqHCIrQeQkkEYqOeJRJVdBjhv5KGJifqT3BFRwX/YFJIChAQpebNQKXe/0kPivWokHWwXlDB7S7mBZzhaAPidZvnuIhalE2qmTypDwHy22FyqV58T8MGGMchcASDi/QXI6kcdpJzPXSeU9o+NC68QDlOIrMVxKFeE7w7PvVmAaxEo0YwmuAzzKy9QpdlK0aab/xEi8V4iXj4hGepqAvHkXIQd+r3FNeiLfllkb61p6WTjr5urcmDQMR94/wYoilpG5OlybHdbhsYHvIzYoLrC7fzl630gcO6t4nM24vdB6Ymg9BVpEgKRAxSbE62Tqacxqnz9AcmgItb48NiR/He3n3ydGjPYuKk/ihZMgEwAEZvSlNxYONSbYrIGDtOY+8Nbt6KiH3l06wjZW8tcmFeVlWv+tWotnTY9IqlAfvNVTjtsobqtQnvsiDjdEVtNy/s2ci5TH+NdZluca2OVEr91Wayxh70kpM6ib4UGbfdmGgCo74gtKvKSJU0rTHakQ5L9JlaSDD5FamBRyI0qfL43Ad9qOUZ8DaffDCyuaVyuqk7cz9HwmEmvWU3VQ+5t06n/5kRDXttcw8w+3qClEEdGo1KeENcnXCB32dQe3tDTFpuAIMLqwXs6FhpawfZ5kPYvLPczGWaqftIs/RXJ/EltGc0ugw2dmTLpoQhCqrcKEBDoYVk0LDZKsnzitOGdi9mOWse7Se8798ib1UsHFUjGzISEt6upestxOeupSTOh0v4+AjXbDzRUyogHww3V+Bqg71bkcMxtB+WM+pn1XNbVTyl9NR040nhP7KEf6e9ruXAtmrBC2ah5cFEpLIot77VFZ9ilLuitSz+7T8n1yAh1IEG6xxXxninAZIzi2qGbH69O5RSpOJuJTv17zTLJQIIc781JwQ2TTwTGnx5wZLbffhCasowJKd2EVcyMJyhz6ru0PvXWJ4hUdkARJs3Xu8dus9a86N8Xk6aAPzBDqzYb1vyFIfBxP0oO8xFHgd30Cgmz8UrSE3qeWRrF8ftrI6xQnFjHBGWD/JWSvd6YMcQED0aVuQkuNW9ST/DzQThPzRfPUoiL10yAmV7Ytu4fR3x2sF0Yfi87YhHFuCMpV/DsqxmUizyiJuD938eRcH8hzR/VO53Qo3UIsqOLcyXtTv6THjSlTopQ+JOLOnHm1w8dzYbLN44OG44rRsbihMUQp+wUZ6bsI8rrOnm9WErzkbQFbrfAINdoCiNa6cimYIjvvnMTaFWNymqY1vZxGztQiMiHiHYwTfwHTXrb9j0uPM=|09J28iXv9oWzYtzK2LBT6Yht4IT4MijEkk0fwFdrVQ4=".parse().unwrap();
client
- .initialize_user_crypto("asdfasdfasdf", user_key.parse().unwrap(), private_key)
+ .initialize_user_crypto_master_key(master_key, user_key.parse().unwrap(), private_key)
.unwrap();
let result = validate_password_user_key(&client, "abc".to_string(), user_key.to_string())
diff --git a/crates/bitwarden/src/client/client.rs b/crates/bitwarden/src/client/client.rs
index 2374d6263..0251723d0 100644
--- a/crates/bitwarden/src/client/client.rs
+++ b/crates/bitwarden/src/client/client.rs
@@ -4,7 +4,7 @@ use std::path::PathBuf;
pub use bitwarden_crypto::Kdf;
use bitwarden_crypto::SymmetricCryptoKey;
#[cfg(feature = "internal")]
-use bitwarden_crypto::{AsymmetricEncString, EncString};
+use bitwarden_crypto::{AsymmetricEncString, EncString, MasterKey};
use chrono::Utc;
use reqwest::header::{self, HeaderValue};
use uuid::Uuid;
@@ -73,6 +73,7 @@ pub(crate) enum ServiceAccountLoginMethod {
},
}
+/// The main struct to interact with the Bitwarden SDK.
#[derive(Debug)]
pub struct Client {
token: Option,
@@ -246,23 +247,14 @@ impl Client {
}
#[cfg(feature = "internal")]
- pub(crate) fn initialize_user_crypto(
+ pub(crate) fn initialize_user_crypto_master_key(
&mut self,
- password: &str,
+ master_key: MasterKey,
user_key: EncString,
private_key: EncString,
) -> Result<&EncryptionSettings> {
- let login_method = match &self.login_method {
- Some(LoginMethod::User(u)) => u,
- _ => return Err(Error::NotAuthenticated),
- };
-
- self.encryption_settings = Some(EncryptionSettings::new(
- login_method,
- password,
- user_key,
- private_key,
- )?);
+ self.encryption_settings =
+ Some(EncryptionSettings::new(master_key, user_key, private_key)?);
Ok(self
.encryption_settings
.as_ref()
@@ -288,20 +280,10 @@ impl Client {
#[cfg(feature = "mobile")]
pub(crate) fn initialize_user_crypto_pin(
&mut self,
- pin: &str,
+ pin_key: MasterKey,
pin_protected_user_key: EncString,
private_key: EncString,
) -> Result<&EncryptionSettings> {
- use bitwarden_crypto::MasterKey;
-
- let pin_key = match &self.login_method {
- Some(LoginMethod::User(
- UserLoginMethod::Username { email, kdf, .. }
- | UserLoginMethod::ApiKey { email, kdf, .. },
- )) => MasterKey::derive(pin.as_bytes(), email.as_bytes(), kdf)?,
- _ => return Err(Error::NotAuthenticated),
- };
-
let decrypted_user_key = pin_key.decrypt_user_key(pin_protected_user_key)?;
self.initialize_user_crypto_decrypted_key(decrypted_user_key, private_key)
}
diff --git a/crates/bitwarden/src/client/encryption_settings.rs b/crates/bitwarden/src/client/encryption_settings.rs
index 6e4da9895..025b3cec7 100644
--- a/crates/bitwarden/src/client/encryption_settings.rs
+++ b/crates/bitwarden/src/client/encryption_settings.rs
@@ -2,11 +2,11 @@ use std::collections::HashMap;
use bitwarden_crypto::{AsymmetricCryptoKey, KeyContainer, SymmetricCryptoKey};
#[cfg(feature = "internal")]
-use bitwarden_crypto::{AsymmetricEncString, EncString};
+use bitwarden_crypto::{AsymmetricEncString, EncString, MasterKey};
use uuid::Uuid;
#[cfg(feature = "internal")]
-use crate::{client::UserLoginMethod, error::Result};
+use crate::error::Result;
pub struct EncryptionSettings {
user_key: SymmetricCryptoKey,
@@ -21,28 +21,16 @@ impl std::fmt::Debug for EncryptionSettings {
}
impl EncryptionSettings {
- /// Initialize the encryption settings with the user password and their encrypted keys
+ /// Initialize the encryption settings with the master key and the encrypted user keys
#[cfg(feature = "internal")]
pub(crate) fn new(
- login_method: &UserLoginMethod,
- password: &str,
+ master_key: MasterKey,
user_key: EncString,
private_key: EncString,
) -> Result {
- use bitwarden_crypto::MasterKey;
-
- match login_method {
- UserLoginMethod::Username { email, kdf, .. }
- | UserLoginMethod::ApiKey { email, kdf, .. } => {
- // Derive master key from password
- let master_key = MasterKey::derive(password.as_bytes(), email.as_bytes(), kdf)?;
-
- // Decrypt the user key
- let user_key = master_key.decrypt_user_key(user_key)?;
-
- Self::new_decrypted_key(user_key, private_key)
- }
- }
+ // Decrypt the user key
+ let user_key = master_key.decrypt_user_key(user_key)?;
+ Self::new_decrypted_key(user_key, private_key)
}
/// Initialize the encryption settings with the decrypted user key and the encrypted user
diff --git a/crates/bitwarden/src/mobile/crypto.rs b/crates/bitwarden/src/mobile/crypto.rs
index b8891aa09..35c38c910 100644
--- a/crates/bitwarden/src/mobile/crypto.rs
+++ b/crates/bitwarden/src/mobile/crypto.rs
@@ -92,19 +92,15 @@ pub async fn initialize_user_crypto(client: &mut Client, req: InitUserCryptoRequ
use crate::auth::{auth_request_decrypt_master_key, auth_request_decrypt_user_key};
- let login_method = crate::client::LoginMethod::User(crate::client::UserLoginMethod::Username {
- client_id: "".to_string(),
- email: req.email,
- kdf: req.kdf_params,
- });
- client.set_login_method(login_method);
-
let private_key: EncString = req.private_key.parse()?;
match req.method {
InitUserCryptoMethod::Password { password, user_key } => {
let user_key: EncString = user_key.parse()?;
- client.initialize_user_crypto(&password, user_key, private_key)?;
+
+ let master_key =
+ MasterKey::derive(password.as_bytes(), req.email.as_bytes(), &req.kdf_params)?;
+ client.initialize_user_crypto_master_key(master_key, user_key, private_key)?;
}
InitUserCryptoMethod::DecryptedKey { decrypted_user_key } => {
let decrypted_user_key = DecryptedString::new(Box::new(decrypted_user_key));
@@ -115,7 +111,8 @@ pub async fn initialize_user_crypto(client: &mut Client, req: InitUserCryptoRequ
pin,
pin_protected_user_key,
} => {
- client.initialize_user_crypto_pin(&pin, pin_protected_user_key, private_key)?;
+ let pin_key = MasterKey::derive(pin.as_bytes(), req.email.as_bytes(), &req.kdf_params)?;
+ client.initialize_user_crypto_pin(pin_key, pin_protected_user_key, private_key)?;
}
InitUserCryptoMethod::AuthRequest {
request_private_key,
@@ -150,6 +147,14 @@ pub async fn initialize_user_crypto(client: &mut Client, req: InitUserCryptoRequ
}
}
+ client.set_login_method(crate::client::LoginMethod::User(
+ crate::client::UserLoginMethod::Username {
+ client_id: "".to_string(),
+ email: req.email,
+ kdf: req.kdf_params,
+ },
+ ));
+
Ok(())
}
@@ -231,9 +236,9 @@ pub fn update_password(
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[cfg_attr(feature = "mobile", derive(uniffi::Record))]
pub struct DerivePinKeyResponse {
- /// [UserKey] protected by PIN
+ /// [UserKey](bitwarden_crypto::UserKey) protected by PIN
pin_protected_user_key: EncString,
- /// PIN protected by [UserKey]
+ /// PIN protected by [UserKey](bitwarden_crypto::UserKey)
encrypted_pin: EncString,
}
@@ -493,18 +498,20 @@ mod tests {
use bitwarden_crypto::AsymmetricCryptoKey;
let mut client = Client::new(None);
- client.set_login_method(LoginMethod::User(UserLoginMethod::Username {
- client_id: "7b821276-e27c-400b-9853-606393c87f18".to_owned(),
- email: "test@bitwarden.com".to_owned(),
- kdf: Kdf::PBKDF2 {
+
+ let master_key = bitwarden_crypto::MasterKey::derive(
+ "asdfasdfasdf".as_bytes(),
+ "test@bitwarden.com".as_bytes(),
+ &Kdf::PBKDF2 {
iterations: NonZeroU32::new(600_000).unwrap(),
},
- }));
+ )
+ .unwrap();
let user_key = "2.Q/2PhzcC7GdeiMHhWguYAQ==|GpqzVdr0go0ug5cZh1n+uixeBC3oC90CIe0hd/HWA/pTRDZ8ane4fmsEIcuc8eMKUt55Y2q/fbNzsYu41YTZzzsJUSeqVjT8/iTQtgnNdpo=|dwI+uyvZ1h/iZ03VQ+/wrGEFYVewBUUl/syYgjsNMbE=".parse().unwrap();
let private_key ="2.yN7l00BOlUE0Sb0M//Q53w==|EwKG/BduQRQ33Izqc/ogoBROIoI5dmgrxSo82sgzgAMIBt3A2FZ9vPRMY+GWT85JiqytDitGR3TqwnFUBhKUpRRAq4x7rA6A1arHrFp5Tp1p21O3SfjtvB3quiOKbqWk6ZaU1Np9HwqwAecddFcB0YyBEiRX3VwF2pgpAdiPbSMuvo2qIgyob0CUoC/h4Bz1be7Qa7B0Xw9/fMKkB1LpOm925lzqosyMQM62YpMGkjMsbZz0uPopu32fxzDWSPr+kekNNyLt9InGhTpxLmq1go/pXR2uw5dfpXc5yuta7DB0EGBwnQ8Vl5HPdDooqOTD9I1jE0mRyuBpWTTI3FRnu3JUh3rIyGBJhUmHqGZvw2CKdqHCIrQeQkkEYqOeJRJVdBjhv5KGJifqT3BFRwX/YFJIChAQpebNQKXe/0kPivWokHWwXlDB7S7mBZzhaAPidZvnuIhalE2qmTypDwHy22FyqV58T8MGGMchcASDi/QXI6kcdpJzPXSeU9o+NC68QDlOIrMVxKFeE7w7PvVmAaxEo0YwmuAzzKy9QpdlK0aab/xEi8V4iXj4hGepqAvHkXIQd+r3FNeiLfllkb61p6WTjr5urcmDQMR94/wYoilpG5OlybHdbhsYHvIzYoLrC7fzl630gcO6t4nM24vdB6Ymg9BVpEgKRAxSbE62Tqacxqnz9AcmgItb48NiR/He3n3ydGjPYuKk/ihZMgEwAEZvSlNxYONSbYrIGDtOY+8Nbt6KiH3l06wjZW8tcmFeVlWv+tWotnTY9IqlAfvNVTjtsobqtQnvsiDjdEVtNy/s2ci5TH+NdZluca2OVEr91Wayxh70kpM6ib4UGbfdmGgCo74gtKvKSJU0rTHakQ5L9JlaSDD5FamBRyI0qfL43Ad9qOUZ8DaffDCyuaVyuqk7cz9HwmEmvWU3VQ+5t06n/5kRDXttcw8w+3qClEEdGo1KeENcnXCB32dQe3tDTFpuAIMLqwXs6FhpawfZ5kPYvLPczGWaqftIs/RXJ/EltGc0ugw2dmTLpoQhCqrcKEBDoYVk0LDZKsnzitOGdi9mOWse7Se8798ib1UsHFUjGzISEt6upestxOeupSTOh0v4+AjXbDzRUyogHww3V+Bqg71bkcMxtB+WM+pn1XNbVTyl9NR040nhP7KEf6e9ruXAtmrBC2ah5cFEpLIot77VFZ9ilLuitSz+7T8n1yAh1IEG6xxXxninAZIzi2qGbH69O5RSpOJuJTv17zTLJQIIc781JwQ2TTwTGnx5wZLbffhCasowJKd2EVcyMJyhz6ru0PvXWJ4hUdkARJs3Xu8dus9a86N8Xk6aAPzBDqzYb1vyFIfBxP0oO8xFHgd30Cgmz8UrSE3qeWRrF8ftrI6xQnFjHBGWD/JWSvd6YMcQED0aVuQkuNW9ST/DzQThPzRfPUoiL10yAmV7Ytu4fR3x2sF0Yfi87YhHFuCMpV/DsqxmUizyiJuD938eRcH8hzR/VO53Qo3UIsqOLcyXtTv6THjSlTopQ+JOLOnHm1w8dzYbLN44OG44rRsbihMUQp+wUZ6bsI8rrOnm9WErzkbQFbrfAINdoCiNa6cimYIjvvnMTaFWNymqY1vZxGztQiMiHiHYwTfwHTXrb9j0uPM=|09J28iXv9oWzYtzK2LBT6Yht4IT4MijEkk0fwFdrVQ4=".parse().unwrap();
client
- .initialize_user_crypto("asdfasdfasdf", user_key, private_key)
+ .initialize_user_crypto_master_key(master_key, user_key, private_key)
.unwrap();
let public_key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsy7RFHcX3C8Q4/OMmhhbFReYWfB45W9PDTEA8tUZwZmtOiN2RErIS2M1c+K/4HoDJ/TjpbX1f2MZcr4nWvKFuqnZXyewFc+jmvKVewYi+NAu2++vqKq2kKcmMNhwoQDQdQIVy/Uqlp4Cpi2cIwO6ogq5nHNJGR3jm+CpyrafYlbz1bPvL3hbyoGDuG2tgADhyhXUdFuef2oF3wMvn1lAJAvJnPYpMiXUFmj1ejmbwtlxZDrHgUJvUcp7nYdwUKaFoi+sOttHn3u7eZPtNvxMjhSS/X/1xBIzP/mKNLdywH5LoRxniokUk+fV3PYUxJsiU3lV0Trc/tH46jqd8ZGjmwIDAQAB";
diff --git a/crates/bitwarden/src/platform/generate_fingerprint.rs b/crates/bitwarden/src/platform/generate_fingerprint.rs
index 59d81d652..b61454f06 100644
--- a/crates/bitwarden/src/platform/generate_fingerprint.rs
+++ b/crates/bitwarden/src/platform/generate_fingerprint.rs
@@ -55,10 +55,7 @@ mod tests {
use std::num::NonZeroU32;
use super::*;
- use crate::{
- client::{Kdf, LoginMethod, UserLoginMethod},
- Client,
- };
+ use crate::{client::Kdf, Client};
#[test]
fn test_generate_user_fingerprint() {
@@ -67,16 +64,19 @@ mod tests {
let fingerprint_material = "a09726a0-9590-49d1-a5f5-afe300b6a515";
let mut client = Client::new(None);
- client.set_login_method(LoginMethod::User(UserLoginMethod::Username {
- client_id: "a09726a0-9590-49d1-a5f5-afe300b6a515".to_owned(),
- email: "robb@stark.com".to_owned(),
- kdf: Kdf::PBKDF2 {
+
+ let master_key = bitwarden_crypto::MasterKey::derive(
+ "asdfasdfasdf".as_bytes(),
+ "robb@stark.com".as_bytes(),
+ &Kdf::PBKDF2 {
iterations: NonZeroU32::new(600_000).unwrap(),
},
- }));
+ )
+ .unwrap();
+
client
- .initialize_user_crypto(
- "asdfasdfasdf",
+ .initialize_user_crypto_master_key(
+ master_key,
user_key.parse().unwrap(),
private_key.parse().unwrap(),
)
diff --git a/crates/bitwarden/src/vault/send.rs b/crates/bitwarden/src/vault/send.rs
index 37e6efcc9..81341d0e3 100644
--- a/crates/bitwarden/src/vault/send.rs
+++ b/crates/bitwarden/src/vault/send.rs
@@ -361,26 +361,27 @@ impl TryFrom for SendText {
#[cfg(test)]
mod tests {
- use bitwarden_crypto::{KeyDecryptable, KeyEncryptable};
+ use bitwarden_crypto::{KeyDecryptable, KeyEncryptable, MasterKey};
use super::{Send, SendText, SendTextView, SendType};
use crate::{
- client::{encryption_settings::EncryptionSettings, Kdf, UserLoginMethod},
+ client::{encryption_settings::EncryptionSettings, Kdf},
vault::SendView,
};
#[test]
fn test_get_send_key() {
// Initialize user encryption with some test data
- let enc = EncryptionSettings::new(
- &UserLoginMethod::Username {
- client_id: "test".into(),
- email: "test@bitwarden.com".into(),
- kdf: Kdf::PBKDF2 {
- iterations: 345123.try_into().unwrap(),
- },
+ let master_key = MasterKey::derive(
+ "asdfasdfasdf".as_bytes(),
+ "test@bitwarden.com".as_bytes(),
+ &Kdf::PBKDF2 {
+ iterations: 345123.try_into().unwrap(),
},
- "asdfasdfasdf",
+ )
+ .unwrap();
+ let enc = EncryptionSettings::new(
+ master_key,
"2.majkL1/hNz9yptLqNAUSnw==|RiOzMTTJMG948qu8O3Zm1EQUO2E8BuTwFKnO9LWQjMzxMWJM5GbyOq2/A+tumPbTERt4JWur/FKfgHb+gXuYiEYlXPMuVBvT7nv4LPytJuM=|IVqMxHJeR1ZXY0sGngTC0x+WqbG8p6V+BTrdgBbQXjM=".parse().unwrap(),
"2.kmLY8NJVuiKBFJtNd/ZFpA==|qOodlRXER+9ogCe3yOibRHmUcSNvjSKhdDuztLlucs10jLiNoVVVAc+9KfNErLSpx5wmUF1hBOJM8zwVPjgQTrmnNf/wuDpwiaCxNYb/0v4FygPy7ccAHK94xP1lfqq7U9+tv+/yiZSwgcT+xF0wFpoxQeNdNRFzPTuD9o4134n8bzacD9DV/WjcrXfRjbBCzzuUGj1e78+A7BWN7/5IWLz87KWk8G7O/W4+8PtEzlwkru6Wd1xO19GYU18oArCWCNoegSmcGn7w7NDEXlwD403oY8Oa7ylnbqGE28PVJx+HLPNIdSC6YKXeIOMnVs7Mctd/wXC93zGxAWD6ooTCzHSPVV50zKJmWIG2cVVUS7j35H3rGDtUHLI+ASXMEux9REZB8CdVOZMzp2wYeiOpggebJy6MKOZqPT1R3X0fqF2dHtRFPXrNsVr1Qt6bS9qTyO4ag1/BCvXF3P1uJEsI812BFAne3cYHy5bIOxuozPfipJrTb5WH35bxhElqwT3y/o/6JWOGg3HLDun31YmiZ2HScAsUAcEkA4hhoTNnqy4O2s3yVbCcR7jF7NLsbQc0MDTbnjxTdI4VnqUIn8s2c9hIJy/j80pmO9Bjxp+LQ9a2hUkfHgFhgHxZUVaeGVth8zG2kkgGdrp5VHhxMVFfvB26Ka6q6qE/UcS2lONSv+4T8niVRJz57qwctj8MNOkA3PTEfe/DP/LKMefke31YfT0xogHsLhDkx+mS8FCc01HReTjKLktk/Jh9mXwC5oKwueWWwlxI935ecn+3I2kAuOfMsgPLkoEBlwgiREC1pM7VVX1x8WmzIQVQTHd4iwnX96QewYckGRfNYWz/zwvWnjWlfcg8kRSe+68EHOGeRtC5r27fWLqRc0HNcjwpgHkI/b6czerCe8+07TWql4keJxJxhBYj3iOH7r9ZS8ck51XnOb8tGL1isimAJXodYGzakwktqHAD7MZhS+P02O+6jrg7d+yPC2ZCuS/3TOplYOCHQIhnZtR87PXTUwr83zfOwAwCyv6KP84JUQ45+DItrXLap7nOVZKQ5QxYIlbThAO6eima6Zu5XHfqGPMNWv0bLf5+vAjIa5np5DJrSwz9no/hj6CUh0iyI+SJq4RGI60lKtypMvF6MR3nHLEHOycRUQbZIyTHWl4QQLdHzuwN9lv10ouTEvNr6sFflAX2yb6w3hlCo7oBytH3rJekjb3IIOzBpeTPIejxzVlh0N9OT5MZdh4sNKYHUoWJ8mnfjdM+L4j5Q2Kgk/XiGDgEebkUxiEOQUdVpePF5uSCE+TPav/9FIRGXGiFn6NJMaU7aBsDTFBLloffFLYDpd8/bTwoSvifkj7buwLYM+h/qcnfdy5FWau1cKav+Blq/ZC0qBpo658RTC8ZtseAFDgXoQZuksM10hpP9bzD04Bx30xTGX81QbaSTNwSEEVrOtIhbDrj9OI43KH4O6zLzK+t30QxAv5zjk10RZ4+5SAdYndIlld9Y62opCfPDzRy3ubdve4ZEchpIKWTQvIxq3T5ogOhGaWBVYnkMtM2GVqvWV//46gET5SH/MdcwhACUcZ9kCpMnWH9CyyUwYvTT3UlNyV+DlS27LMPvaw7tx7qa+GfNCoCBd8S4esZpQYK/WReiS8=|pc7qpD42wxyXemdNPuwxbh8iIaryrBPu8f/DGwYdHTw=".parse().unwrap(),
).unwrap();
@@ -398,15 +399,17 @@ mod tests {
}
fn build_encryption_settings() -> EncryptionSettings {
- EncryptionSettings::new(
- &UserLoginMethod::Username {
- client_id: "test".into(),
- email: "test@bitwarden.com".into(),
- kdf: Kdf::PBKDF2 {
- iterations: 600_000.try_into().unwrap(),
- },
+ let master_key = MasterKey::derive(
+ "asdfasdfasdf".as_bytes(),
+ "test@bitwarden.com".as_bytes(),
+ &Kdf::PBKDF2 {
+ iterations: 600_000.try_into().unwrap(),
},
- "asdfasdfasdf",
+ )
+ .unwrap();
+
+ EncryptionSettings::new(
+ master_key,
"2.Q/2PhzcC7GdeiMHhWguYAQ==|GpqzVdr0go0ug5cZh1n+uixeBC3oC90CIe0hd/HWA/pTRDZ8ane4fmsEIcuc8eMKUt55Y2q/fbNzsYu41YTZzzsJUSeqVjT8/iTQtgnNdpo=|dwI+uyvZ1h/iZ03VQ+/wrGEFYVewBUUl/syYgjsNMbE=".parse().unwrap(),
"2.yN7l00BOlUE0Sb0M//Q53w==|EwKG/BduQRQ33Izqc/ogoBROIoI5dmgrxSo82sgzgAMIBt3A2FZ9vPRMY+GWT85JiqytDitGR3TqwnFUBhKUpRRAq4x7rA6A1arHrFp5Tp1p21O3SfjtvB3quiOKbqWk6ZaU1Np9HwqwAecddFcB0YyBEiRX3VwF2pgpAdiPbSMuvo2qIgyob0CUoC/h4Bz1be7Qa7B0Xw9/fMKkB1LpOm925lzqosyMQM62YpMGkjMsbZz0uPopu32fxzDWSPr+kekNNyLt9InGhTpxLmq1go/pXR2uw5dfpXc5yuta7DB0EGBwnQ8Vl5HPdDooqOTD9I1jE0mRyuBpWTTI3FRnu3JUh3rIyGBJhUmHqGZvw2CKdqHCIrQeQkkEYqOeJRJVdBjhv5KGJifqT3BFRwX/YFJIChAQpebNQKXe/0kPivWokHWwXlDB7S7mBZzhaAPidZvnuIhalE2qmTypDwHy22FyqV58T8MGGMchcASDi/QXI6kcdpJzPXSeU9o+NC68QDlOIrMVxKFeE7w7PvVmAaxEo0YwmuAzzKy9QpdlK0aab/xEi8V4iXj4hGepqAvHkXIQd+r3FNeiLfllkb61p6WTjr5urcmDQMR94/wYoilpG5OlybHdbhsYHvIzYoLrC7fzl630gcO6t4nM24vdB6Ymg9BVpEgKRAxSbE62Tqacxqnz9AcmgItb48NiR/He3n3ydGjPYuKk/ihZMgEwAEZvSlNxYONSbYrIGDtOY+8Nbt6KiH3l06wjZW8tcmFeVlWv+tWotnTY9IqlAfvNVTjtsobqtQnvsiDjdEVtNy/s2ci5TH+NdZluca2OVEr91Wayxh70kpM6ib4UGbfdmGgCo74gtKvKSJU0rTHakQ5L9JlaSDD5FamBRyI0qfL43Ad9qOUZ8DaffDCyuaVyuqk7cz9HwmEmvWU3VQ+5t06n/5kRDXttcw8w+3qClEEdGo1KeENcnXCB32dQe3tDTFpuAIMLqwXs6FhpawfZ5kPYvLPczGWaqftIs/RXJ/EltGc0ugw2dmTLpoQhCqrcKEBDoYVk0LDZKsnzitOGdi9mOWse7Se8798ib1UsHFUjGzISEt6upestxOeupSTOh0v4+AjXbDzRUyogHww3V+Bqg71bkcMxtB+WM+pn1XNbVTyl9NR040nhP7KEf6e9ruXAtmrBC2ah5cFEpLIot77VFZ9ilLuitSz+7T8n1yAh1IEG6xxXxninAZIzi2qGbH69O5RSpOJuJTv17zTLJQIIc781JwQ2TTwTGnx5wZLbffhCasowJKd2EVcyMJyhz6ru0PvXWJ4hUdkARJs3Xu8dus9a86N8Xk6aAPzBDqzYb1vyFIfBxP0oO8xFHgd30Cgmz8UrSE3qeWRrF8ftrI6xQnFjHBGWD/JWSvd6YMcQED0aVuQkuNW9ST/DzQThPzRfPUoiL10yAmV7Ytu4fR3x2sF0Yfi87YhHFuCMpV/DsqxmUizyiJuD938eRcH8hzR/VO53Qo3UIsqOLcyXtTv6THjSlTopQ+JOLOnHm1w8dzYbLN44OG44rRsbihMUQp+wUZ6bsI8rrOnm9WErzkbQFbrfAINdoCiNa6cimYIjvvnMTaFWNymqY1vZxGztQiMiHiHYwTfwHTXrb9j0uPM=|09J28iXv9oWzYtzK2LBT6Yht4IT4MijEkk0fwFdrVQ4=".parse().unwrap(),
).unwrap()