bitwarden_core/key_management/
crypto_client.rs1#[cfg(feature = "wasm")]
2use bitwarden_crypto::safe::PasswordProtectedKeyEnvelope;
3use bitwarden_crypto::{CryptoError, Decryptable, Kdf, RotateableKeySet};
4#[cfg(feature = "internal")]
5use bitwarden_crypto::{EncString, UnsignedSharedKey};
6use bitwarden_encoding::B64;
7#[cfg(feature = "wasm")]
8use wasm_bindgen::prelude::*;
9
10use super::crypto::{
11 DeriveKeyConnectorError, DeriveKeyConnectorRequest, EnrollAdminPasswordResetError,
12 MakeKeyPairResponse, VerifyAsymmetricKeysRequest, VerifyAsymmetricKeysResponse,
13 derive_key_connector, make_key_pair, verify_asymmetric_keys,
14};
15#[cfg(feature = "internal")]
16use crate::key_management::{
17 SymmetricKeyId,
18 crypto::{
19 DerivePinKeyResponse, InitOrgCryptoRequest, InitUserCryptoRequest, UpdatePasswordResponse,
20 derive_pin_key, derive_pin_user_key, enroll_admin_password_reset, get_user_encryption_key,
21 initialize_org_crypto, initialize_user_crypto, make_prf_user_key_set,
22 },
23};
24use crate::{
25 Client, UserId,
26 client::encryption_settings::EncryptionSettingsError,
27 error::StatefulCryptoError,
28 key_management::crypto::{
29 CryptoClientError, EnrollPinResponse, MakeKeysError, MakeTdeRegistrationResponse,
30 UpdateKdfResponse, UserCryptoV2KeysResponse, enroll_pin, get_v2_rotated_account_keys,
31 make_update_kdf, make_update_password, make_user_tde_registration,
32 make_v2_keys_for_v1_user,
33 },
34};
35
36#[cfg_attr(feature = "wasm", wasm_bindgen)]
38pub struct CryptoClient {
39 pub(crate) client: crate::Client,
40}
41
42#[cfg_attr(feature = "wasm", wasm_bindgen)]
43impl CryptoClient {
44 pub async fn initialize_user_crypto(
47 &self,
48 req: InitUserCryptoRequest,
49 ) -> Result<(), EncryptionSettingsError> {
50 initialize_user_crypto(&self.client, req).await
51 }
52
53 pub async fn initialize_org_crypto(
56 &self,
57 req: InitOrgCryptoRequest,
58 ) -> Result<(), EncryptionSettingsError> {
59 initialize_org_crypto(&self.client, req).await
60 }
61
62 pub fn make_key_pair(&self, user_key: B64) -> Result<MakeKeyPairResponse, CryptoError> {
65 make_key_pair(user_key)
66 }
67
68 pub fn verify_asymmetric_keys(
72 &self,
73 request: VerifyAsymmetricKeysRequest,
74 ) -> Result<VerifyAsymmetricKeysResponse, CryptoError> {
75 verify_asymmetric_keys(request)
76 }
77
78 pub fn make_keys_for_user_crypto_v2(
80 &self,
81 ) -> Result<UserCryptoV2KeysResponse, StatefulCryptoError> {
82 make_v2_keys_for_v1_user(&self.client)
83 }
84
85 pub fn get_v2_rotated_account_keys(
87 &self,
88 ) -> Result<UserCryptoV2KeysResponse, StatefulCryptoError> {
89 get_v2_rotated_account_keys(&self.client)
90 }
91
92 pub fn make_update_kdf(
96 &self,
97 password: String,
98 kdf: Kdf,
99 ) -> Result<UpdateKdfResponse, CryptoClientError> {
100 make_update_kdf(&self.client, &password, &kdf)
101 }
102
103 pub fn enroll_pin(&self, pin: String) -> Result<EnrollPinResponse, CryptoClientError> {
107 enroll_pin(&self.client, pin)
108 }
109
110 pub fn enroll_pin_with_encrypted_pin(
114 &self,
115 encrypted_pin: String,
117 ) -> Result<EnrollPinResponse, CryptoClientError> {
118 let encrypted_pin: EncString = encrypted_pin.parse()?;
119 let pin = encrypted_pin.decrypt(
120 &mut self.client.internal.get_key_store().context_mut(),
121 SymmetricKeyId::User,
122 )?;
123 enroll_pin(&self.client, pin)
124 }
125
126 #[cfg(any(feature = "wasm", test))]
129 pub fn unseal_password_protected_key_envelope(
130 &self,
131 pin: String,
132 envelope: PasswordProtectedKeyEnvelope,
133 ) -> Result<Vec<u8>, CryptoClientError> {
134 let mut ctx = self.client.internal.get_key_store().context_mut();
135 let key_slot = envelope.unseal(pin.as_str(), &mut ctx)?;
136 #[allow(deprecated)]
137 let key = ctx.dangerous_get_symmetric_key(key_slot)?;
138 Ok(key.to_encoded().to_vec())
139 }
140}
141
142impl CryptoClient {
143 pub async fn get_user_encryption_key(&self) -> Result<B64, CryptoClientError> {
146 get_user_encryption_key(&self.client).await
147 }
148
149 pub fn make_update_password(
153 &self,
154 new_password: String,
155 ) -> Result<UpdatePasswordResponse, CryptoClientError> {
156 make_update_password(&self.client, new_password)
157 }
158
159 pub fn derive_pin_key(&self, pin: String) -> Result<DerivePinKeyResponse, CryptoClientError> {
163 derive_pin_key(&self.client, pin)
164 }
165
166 pub fn derive_pin_user_key(
169 &self,
170 encrypted_pin: EncString,
171 ) -> Result<EncString, CryptoClientError> {
172 derive_pin_user_key(&self.client, encrypted_pin)
173 }
174
175 pub fn make_prf_user_key_set(&self, prf: B64) -> Result<RotateableKeySet, CryptoClientError> {
178 make_prf_user_key_set(&self.client, prf)
179 }
180
181 pub fn enroll_admin_password_reset(
184 &self,
185 public_key: B64,
186 ) -> Result<UnsignedSharedKey, EnrollAdminPasswordResetError> {
187 enroll_admin_password_reset(&self.client, public_key)
188 }
189
190 pub fn derive_key_connector(
192 &self,
193 request: DeriveKeyConnectorRequest,
194 ) -> Result<B64, DeriveKeyConnectorError> {
195 derive_key_connector(request)
196 }
197
198 pub fn make_user_tde_registration(
202 &self,
203 user_id: UserId,
204 org_public_key: B64,
205 ) -> Result<MakeTdeRegistrationResponse, MakeKeysError> {
206 make_user_tde_registration(&self.client, user_id, org_public_key)
207 }
208}
209
210impl Client {
211 pub fn crypto(&self) -> CryptoClient {
213 CryptoClient {
214 client: self.clone(),
215 }
216 }
217}
218
219#[cfg(test)]
220mod tests {
221 use bitwarden_crypto::{BitwardenLegacyKeyBytes, SymmetricCryptoKey};
222
223 use super::*;
224 use crate::client::test_accounts::test_bitwarden_com_account;
225
226 #[tokio::test]
227 async fn test_enroll_pin_envelope() {
228 let client = Client::init_test_account(test_bitwarden_com_account()).await;
230 let user_key_initial =
231 SymmetricCryptoKey::try_from(client.crypto().get_user_encryption_key().await.unwrap())
232 .unwrap();
233
234 let pin = "1234";
236 let enroll_response = client.crypto().enroll_pin(pin.to_string()).unwrap();
237 let re_enroll_response = client
238 .crypto()
239 .enroll_pin_with_encrypted_pin(enroll_response.user_key_encrypted_pin.to_string())
240 .unwrap();
241
242 let secret = BitwardenLegacyKeyBytes::from(
243 client
244 .crypto()
245 .unseal_password_protected_key_envelope(
246 pin.to_string(),
247 re_enroll_response.pin_protected_user_key_envelope,
248 )
249 .unwrap(),
250 );
251 let user_key_final = SymmetricCryptoKey::try_from(&secret).expect("valid user key");
252 assert_eq!(user_key_initial, user_key_final);
253 }
254}