Skip to content

Commit

Permalink
Add derive_protected_pin_key
Browse files Browse the repository at this point in the history
  • Loading branch information
Hinton committed Jan 15, 2024
1 parent 1028efd commit 8851145
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 20 deletions.
18 changes: 16 additions & 2 deletions crates/bitwarden-uniffi/src/crypto.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::sync::Arc;

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

use crate::{error::Result, Client};
Expand Down Expand Up @@ -53,4 +54,17 @@ impl ClientCrypto {
pub async fn derive_pin_key(&self, pin: String) -> Result<DerivePinKeyResponse> {
Ok(self.0 .0.write().await.crypto().derive_pin_key(pin).await?)
}

///
/// to initialize another client instance by using the PIN and the PIN key with `initialize_user_crypto`.
pub async fn derive_protected_pin_key(&self, encrypted_pin: EncString) -> Result<EncString> {
Ok(self
.0
.0
.write()
.await
.crypto()
.derive_protected_pin_key(encrypted_pin)
.await?)
}

Check warning on line 69 in crates/bitwarden-uniffi/src/crypto.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-uniffi/src/crypto.rs#L60-L69

Added lines #L60 - L69 were not covered by tests
}
13 changes: 11 additions & 2 deletions crates/bitwarden/src/mobile/client_crypto.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use crate::Client;
#[cfg(feature = "internal")]
use crate::{
crypto::EncString,
error::Result,
mobile::crypto::{
derive_pin_key, get_user_encryption_key, initialize_org_crypto, initialize_user_crypto,
DerivePinKeyResponse, InitOrgCryptoRequest, InitUserCryptoRequest,
derive_pin_key, derive_protected_pin_key, get_user_encryption_key, initialize_org_crypto,
initialize_user_crypto, DerivePinKeyResponse, InitOrgCryptoRequest, InitUserCryptoRequest,
},
};

Expand Down Expand Up @@ -32,6 +33,14 @@ impl<'a> ClientCrypto<'a> {
pub async fn derive_pin_key(&mut self, pin: String) -> Result<DerivePinKeyResponse> {
derive_pin_key(self.client, pin)
}

#[cfg(feature = "internal")]
pub async fn derive_protected_pin_key(
&mut self,
encrypted_pin: EncString,
) -> Result<EncString> {
derive_protected_pin_key(self.client, encrypted_pin)
}

Check warning on line 43 in crates/bitwarden/src/mobile/client_crypto.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden/src/mobile/client_crypto.rs#L38-L43

Added lines #L38 - L43 were not covered by tests
}

impl<'a> Client {
Expand Down
70 changes: 54 additions & 16 deletions crates/bitwarden/src/mobile/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ use crate::{
Client,
};

#[cfg(feature = "internal")]
use crate::{
client::{LoginMethod, UserLoginMethod},
crypto::{KeyEncryptable, MasterKey, SymmetricCryptoKey},
};

#[cfg(feature = "internal")]
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
Expand Down Expand Up @@ -50,8 +56,6 @@ pub enum InitUserCryptoMethod {

#[cfg(feature = "internal")]
pub async fn initialize_user_crypto(client: &mut Client, req: InitUserCryptoRequest) -> Result<()> {
use crate::crypto::SymmetricCryptoKey;

let login_method = crate::client::LoginMethod::User(crate::client::UserLoginMethod::Username {
client_id: "".to_string(),
email: req.email,
Expand Down Expand Up @@ -112,36 +116,70 @@ pub async fn get_user_encryption_key(client: &mut Client) -> Result<String> {
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[cfg_attr(feature = "mobile", derive(uniffi::Record))]
pub struct DerivePinKeyResponse {
/// [UserKey] protected by PIN
pin_protected_user_key: EncString,
/// PIN protected [UserKey]
encrypted_pin: EncString,
}

#[cfg(feature = "internal")]
pub fn derive_pin_key(client: &mut Client, pin: String) -> Result<DerivePinKeyResponse> {
use crate::{
client::{LoginMethod, UserLoginMethod},
crypto::{KeyEncryptable, MasterKey},
};

let derived_key = match &client.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 user_key = client
.get_encryption_settings()?
.get_key(&None)
.ok_or(Error::VaultLocked)?;

let login_method = client
.login_method
.as_ref()
.ok_or(Error::NotAuthenticated)?;

let pin_protected_user_key = derive_pin_protected_user_key(&pin, login_method, user_key)?;

Ok(DerivePinKeyResponse {
pin_protected_user_key: derived_key.encrypt_user_key(user_key)?,
pin_protected_user_key,
encrypted_pin: pin.encrypt_with_key(user_key)?,
})
}

#[cfg(feature = "internal")]
pub fn derive_protected_pin_key(
client: &mut Client,
encrypted_pin: EncString,
) -> Result<EncString> {

Check warning on line 149 in crates/bitwarden/src/mobile/crypto.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden/src/mobile/crypto.rs#L146-L149

Added lines #L146 - L149 were not covered by tests
use crate::crypto::KeyDecryptable;

let user_key = client
.get_encryption_settings()?
.get_key(&None)
.ok_or(Error::VaultLocked)?;

Check warning on line 155 in crates/bitwarden/src/mobile/crypto.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden/src/mobile/crypto.rs#L152-L155

Added lines #L152 - L155 were not covered by tests

let pin: String = encrypted_pin.decrypt_with_key(user_key)?;
let login_method = client
.login_method
.as_ref()
.ok_or(Error::NotAuthenticated)?;

Check warning on line 161 in crates/bitwarden/src/mobile/crypto.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden/src/mobile/crypto.rs#L157-L161

Added lines #L157 - L161 were not covered by tests

derive_pin_protected_user_key(&pin, login_method, user_key)
}

Check warning on line 164 in crates/bitwarden/src/mobile/crypto.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden/src/mobile/crypto.rs#L163-L164

Added lines #L163 - L164 were not covered by tests

#[cfg(feature = "internal")]
fn derive_pin_protected_user_key(
pin: &str,
login_method: &LoginMethod,
user_key: &SymmetricCryptoKey,
) -> Result<EncString> {
let derived_key = match login_method {
LoginMethod::User(
UserLoginMethod::Username { email, kdf, .. }
| UserLoginMethod::ApiKey { email, kdf, .. },

Check warning on line 175 in crates/bitwarden/src/mobile/crypto.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden/src/mobile/crypto.rs#L175

Added line #L175 was not covered by tests
) => MasterKey::derive(pin.as_bytes(), email.as_bytes(), kdf)?,
_ => return Err(Error::NotAuthenticated),

Check warning on line 177 in crates/bitwarden/src/mobile/crypto.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden/src/mobile/crypto.rs#L177

Added line #L177 was not covered by tests
};

derived_key.encrypt_user_key(user_key)
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down

0 comments on commit 8851145

Please sign in to comment.