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 MakeJitMasterPasswordRegistrationResponse, MakeKeyConnectorRegistrationResponse,
13 MakeKeyPairResponse, VerifyAsymmetricKeysRequest, VerifyAsymmetricKeysResponse,
14 derive_key_connector, make_key_pair, make_user_jit_master_password_registration,
15 make_user_key_connector_registration, verify_asymmetric_keys,
16};
17#[cfg(feature = "internal")]
18use crate::key_management::{
19 SymmetricKeyId,
20 crypto::{
21 DerivePinKeyResponse, InitOrgCryptoRequest, InitUserCryptoRequest, UpdatePasswordResponse,
22 derive_pin_key, derive_pin_user_key, enroll_admin_password_reset, get_user_encryption_key,
23 initialize_org_crypto, initialize_user_crypto, make_prf_user_key_set,
24 },
25};
26#[expect(deprecated)]
27use crate::{
28 Client, UserId,
29 client::encryption_settings::EncryptionSettingsError,
30 error::StatefulCryptoError,
31 key_management::crypto::{
32 CryptoClientError, EnrollPinResponse, MakeKeysError, MakeTdeRegistrationResponse,
33 UpdateKdfResponse, UserCryptoV2KeysResponse, enroll_pin, get_v2_rotated_account_keys,
34 make_update_kdf, make_update_password, make_user_tde_registration,
35 make_v2_keys_for_v1_user,
36 },
37};
38
39#[cfg_attr(feature = "wasm", wasm_bindgen)]
41pub struct CryptoClient {
42 pub(crate) client: crate::Client,
43}
44
45#[cfg_attr(feature = "wasm", wasm_bindgen)]
46impl CryptoClient {
47 pub async fn initialize_user_crypto(
50 &self,
51 req: InitUserCryptoRequest,
52 ) -> Result<(), EncryptionSettingsError> {
53 initialize_user_crypto(&self.client, req).await
54 }
55
56 pub async fn initialize_org_crypto(
59 &self,
60 req: InitOrgCryptoRequest,
61 ) -> Result<(), EncryptionSettingsError> {
62 initialize_org_crypto(&self.client, req).await
63 }
64
65 pub fn make_key_pair(&self, user_key: B64) -> Result<MakeKeyPairResponse, CryptoError> {
68 make_key_pair(user_key)
69 }
70
71 pub fn verify_asymmetric_keys(
75 &self,
76 request: VerifyAsymmetricKeysRequest,
77 ) -> Result<VerifyAsymmetricKeysResponse, CryptoError> {
78 verify_asymmetric_keys(request)
79 }
80
81 pub fn make_keys_for_user_crypto_v2(
83 &self,
84 ) -> Result<UserCryptoV2KeysResponse, StatefulCryptoError> {
85 #[expect(deprecated)]
86 make_v2_keys_for_v1_user(&self.client)
87 }
88
89 pub fn get_v2_rotated_account_keys(
91 &self,
92 ) -> Result<UserCryptoV2KeysResponse, StatefulCryptoError> {
93 #[expect(deprecated)]
94 get_v2_rotated_account_keys(&self.client)
95 }
96
97 pub fn make_update_kdf(
101 &self,
102 password: String,
103 kdf: Kdf,
104 ) -> Result<UpdateKdfResponse, CryptoClientError> {
105 make_update_kdf(&self.client, &password, &kdf)
106 }
107
108 pub fn enroll_pin(&self, pin: String) -> Result<EnrollPinResponse, CryptoClientError> {
112 enroll_pin(&self.client, pin)
113 }
114
115 pub fn enroll_pin_with_encrypted_pin(
119 &self,
120 encrypted_pin: String,
122 ) -> Result<EnrollPinResponse, CryptoClientError> {
123 let encrypted_pin: EncString = encrypted_pin.parse()?;
124 let pin = encrypted_pin.decrypt(
125 &mut self.client.internal.get_key_store().context_mut(),
126 SymmetricKeyId::User,
127 )?;
128 enroll_pin(&self.client, pin)
129 }
130
131 #[cfg(any(feature = "wasm", test))]
134 pub fn unseal_password_protected_key_envelope(
135 &self,
136 pin: String,
137 envelope: PasswordProtectedKeyEnvelope,
138 ) -> Result<Vec<u8>, CryptoClientError> {
139 let mut ctx = self.client.internal.get_key_store().context_mut();
140 let key_slot = envelope.unseal(pin.as_str(), &mut ctx)?;
141 #[allow(deprecated)]
142 let key = ctx.dangerous_get_symmetric_key(key_slot)?;
143 Ok(key.to_encoded().to_vec())
144 }
145}
146
147impl CryptoClient {
148 pub async fn get_user_encryption_key(&self) -> Result<B64, CryptoClientError> {
151 get_user_encryption_key(&self.client).await
152 }
153
154 pub fn make_update_password(
158 &self,
159 new_password: String,
160 ) -> Result<UpdatePasswordResponse, CryptoClientError> {
161 make_update_password(&self.client, new_password)
162 }
163
164 pub fn derive_pin_key(&self, pin: String) -> Result<DerivePinKeyResponse, CryptoClientError> {
168 derive_pin_key(&self.client, pin)
169 }
170
171 pub fn derive_pin_user_key(
174 &self,
175 encrypted_pin: EncString,
176 ) -> Result<EncString, CryptoClientError> {
177 derive_pin_user_key(&self.client, encrypted_pin)
178 }
179
180 pub fn make_prf_user_key_set(&self, prf: B64) -> Result<RotateableKeySet, CryptoClientError> {
183 make_prf_user_key_set(&self.client, prf)
184 }
185
186 pub fn enroll_admin_password_reset(
189 &self,
190 public_key: B64,
191 ) -> Result<UnsignedSharedKey, EnrollAdminPasswordResetError> {
192 enroll_admin_password_reset(&self.client, public_key)
193 }
194
195 pub fn derive_key_connector(
197 &self,
198 request: DeriveKeyConnectorRequest,
199 ) -> Result<B64, DeriveKeyConnectorError> {
200 derive_key_connector(request)
201 }
202
203 pub fn make_user_tde_registration(
207 &self,
208 user_id: UserId,
209 org_public_key: B64,
210 ) -> Result<MakeTdeRegistrationResponse, MakeKeysError> {
211 make_user_tde_registration(&self.client, user_id, org_public_key)
212 }
213
214 pub fn make_user_key_connector_registration(
218 &self,
219 user_id: UserId,
220 ) -> Result<MakeKeyConnectorRegistrationResponse, MakeKeysError> {
221 make_user_key_connector_registration(&self.client, user_id)
222 }
223
224 pub fn make_user_jit_master_password_registration(
228 &self,
229 user_id: UserId,
230 master_password: String,
231 salt: String,
232 org_public_key: B64,
233 ) -> Result<MakeJitMasterPasswordRegistrationResponse, MakeKeysError> {
234 make_user_jit_master_password_registration(
235 &self.client,
236 user_id,
237 master_password,
238 salt,
239 org_public_key,
240 )
241 }
242}
243
244impl Client {
245 pub fn crypto(&self) -> CryptoClient {
247 CryptoClient {
248 client: self.clone(),
249 }
250 }
251}
252
253#[cfg(test)]
254mod tests {
255 use bitwarden_crypto::{BitwardenLegacyKeyBytes, SymmetricCryptoKey};
256
257 use super::*;
258 use crate::client::test_accounts::test_bitwarden_com_account;
259
260 #[tokio::test]
261 async fn test_enroll_pin_envelope() {
262 let client = Client::init_test_account(test_bitwarden_com_account()).await;
264 let user_key_initial =
265 SymmetricCryptoKey::try_from(client.crypto().get_user_encryption_key().await.unwrap())
266 .unwrap();
267
268 let pin = "1234";
270 let enroll_response = client.crypto().enroll_pin(pin.to_string()).unwrap();
271 let re_enroll_response = client
272 .crypto()
273 .enroll_pin_with_encrypted_pin(enroll_response.user_key_encrypted_pin.to_string())
274 .unwrap();
275
276 let secret = BitwardenLegacyKeyBytes::from(
277 client
278 .crypto()
279 .unseal_password_protected_key_envelope(
280 pin.to_string(),
281 re_enroll_response.pin_protected_user_key_envelope,
282 )
283 .unwrap(),
284 );
285 let user_key_final = SymmetricCryptoKey::try_from(&secret).expect("valid user key");
286 assert_eq!(user_key_initial, user_key_final);
287 }
288}