bitwarden_core/client/
encryption_settings.rs1#[cfg(feature = "internal")]
2use std::sync::RwLock;
3
4#[cfg(feature = "internal")]
5use bitwarden_crypto::{
6 Aes256CbcHmacKey, AsymmetricCryptoKey, CoseKeyBytes, CoseSerializable, EncString,
7 KeyDecryptable, Pkcs8PrivateKeyBytes, SigningKey, UnsignedSharedKey, XChaCha20Poly1305Key,
8};
9#[cfg(any(feature = "internal", feature = "secrets"))]
10use bitwarden_crypto::{KeyStore, SymmetricCryptoKey};
11use bitwarden_error::bitwarden_error;
12#[cfg(feature = "internal")]
13use log::warn;
14use thiserror::Error;
15
16#[cfg(feature = "internal")]
17use crate::key_management::{AsymmetricKeyId, SecurityState, SignedSecurityState, SigningKeyId};
18#[cfg(any(feature = "internal", feature = "secrets"))]
19use crate::key_management::{KeyIds, SymmetricKeyId};
20#[cfg(any(feature = "secrets", feature = "internal"))]
21use crate::OrganizationId;
22use crate::{error::UserIdAlreadySetError, MissingPrivateKeyError};
23
24#[allow(missing_docs)]
25#[bitwarden_error(flat)]
26#[derive(Debug, Error)]
27pub enum EncryptionSettingsError {
28 #[error("Cryptography error, {0}")]
29 Crypto(#[from] bitwarden_crypto::CryptoError),
30
31 #[error("Invalid private key")]
32 InvalidPrivateKey,
33
34 #[error("Invalid signing key")]
35 InvalidSigningKey,
36
37 #[error("Invalid security state")]
38 InvalidSecurityState,
39
40 #[error(transparent)]
41 MissingPrivateKey(#[from] MissingPrivateKeyError),
42
43 #[error(transparent)]
44 UserIdAlreadySet(#[from] UserIdAlreadySetError),
45
46 #[error("Wrong Pin")]
47 WrongPin,
48}
49
50#[allow(clippy::large_enum_variant)]
51#[cfg(feature = "internal")]
52pub(crate) enum AccountEncryptionKeys {
53 V1 {
54 user_key: Aes256CbcHmacKey,
55 private_key: EncString,
56 },
57 V2 {
58 user_key: XChaCha20Poly1305Key,
59 private_key: EncString,
60 signing_key: EncString,
61 security_state: SignedSecurityState,
62 },
63}
64
65#[allow(missing_docs)]
66pub struct EncryptionSettings {}
67
68impl EncryptionSettings {
69 #[cfg(feature = "internal")]
74 pub(crate) fn new_decrypted_key(
75 encryption_keys: AccountEncryptionKeys,
76 store: &KeyStore<KeyIds>,
77 security_state_rwlock: &RwLock<Option<SecurityState>>,
78 ) -> Result<(), EncryptionSettingsError> {
79 match encryption_keys {
84 AccountEncryptionKeys::V1 {
85 user_key,
86 private_key,
87 } => {
88 Self::init_v1(user_key, private_key, store)?;
89 }
90 AccountEncryptionKeys::V2 {
91 user_key,
92 private_key,
93 signing_key,
94 security_state,
95 } => {
96 Self::init_v2(
97 user_key,
98 private_key,
99 signing_key,
100 security_state,
101 store,
102 security_state_rwlock,
103 )?;
104 }
105 }
106
107 Ok(())
108 }
109
110 #[cfg(feature = "internal")]
111 fn init_v1(
112 user_key: Aes256CbcHmacKey,
113 private_key: EncString,
114 store: &KeyStore<KeyIds>,
115 ) -> Result<(), EncryptionSettingsError> {
116 let user_key = SymmetricCryptoKey::Aes256CbcHmacKey(user_key);
117
118 let private_key = {
119 let dec: Vec<u8> = private_key.decrypt_with_key(&user_key)?;
120
121 AsymmetricCryptoKey::from_der(&Pkcs8PrivateKeyBytes::from(dec))
124 .map_err(|_| {
125 warn!("Invalid private key");
126 })
127 .ok()
128
129 };
134
135 #[allow(deprecated)]
137 {
138 let mut ctx = store.context_mut();
139 ctx.set_symmetric_key(SymmetricKeyId::User, user_key)?;
140 if let Some(private_key) = private_key {
141 ctx.set_asymmetric_key(AsymmetricKeyId::UserPrivateKey, private_key)?;
142 }
143 }
144
145 Ok(())
146 }
147
148 #[cfg(feature = "internal")]
149 fn init_v2(
150 user_key: XChaCha20Poly1305Key,
151 private_key: EncString,
152 signing_key: EncString,
153 security_state: SignedSecurityState,
154 store: &KeyStore<KeyIds>,
155 sdk_security_state: &RwLock<Option<SecurityState>>,
156 ) -> Result<(), EncryptionSettingsError> {
157 use crate::key_management::SecurityState;
158
159 let user_key = SymmetricCryptoKey::XChaCha20Poly1305Key(user_key);
160
161 let signing_key: Vec<u8> = signing_key.decrypt_with_key(&user_key)?;
164 let signing_key = SigningKey::from_cose(&CoseKeyBytes::from(signing_key))
165 .map_err(|_| EncryptionSettingsError::InvalidSigningKey)?;
166 let private_key: Vec<u8> = private_key.decrypt_with_key(&user_key)?;
167 let private_key = AsymmetricCryptoKey::from_der(&Pkcs8PrivateKeyBytes::from(private_key))
168 .map_err(|_| EncryptionSettingsError::InvalidPrivateKey)?;
169
170 let security_state: SecurityState = security_state
171 .verify_and_unwrap(&signing_key.to_verifying_key())
172 .map_err(|_| EncryptionSettingsError::InvalidSecurityState)?;
173 *sdk_security_state.write().expect("RwLock not poisoned") = Some(security_state);
174
175 #[allow(deprecated)]
176 {
177 let mut ctx = store.context_mut();
178 ctx.set_symmetric_key(SymmetricKeyId::User, user_key)?;
179 ctx.set_asymmetric_key(AsymmetricKeyId::UserPrivateKey, private_key)?;
180 ctx.set_signing_key(SigningKeyId::UserSigningKey, signing_key)?;
181 }
182
183 Ok(())
184 }
185
186 #[cfg(feature = "secrets")]
189 pub(crate) fn new_single_org_key(
190 organization_id: OrganizationId,
191 key: SymmetricCryptoKey,
192 store: &KeyStore<KeyIds>,
193 ) {
194 #[allow(deprecated)]
196 store
197 .context_mut()
198 .set_symmetric_key(SymmetricKeyId::Organization(organization_id), key)
199 .expect("Mutable context");
200 }
201
202 #[cfg(feature = "internal")]
203 pub(crate) fn set_org_keys(
204 org_enc_keys: Vec<(OrganizationId, UnsignedSharedKey)>,
205 store: &KeyStore<KeyIds>,
206 ) -> Result<(), EncryptionSettingsError> {
207 use crate::key_management::AsymmetricKeyId;
208
209 let mut ctx = store.context_mut();
210
211 if org_enc_keys.is_empty() {
213 return Ok(());
214 }
215
216 if !ctx.has_asymmetric_key(AsymmetricKeyId::UserPrivateKey) {
217 return Err(MissingPrivateKeyError.into());
218 }
219
220 ctx.retain_symmetric_keys(|key_ref| !matches!(key_ref, SymmetricKeyId::Organization(_)));
223
224 for (org_id, org_enc_key) in org_enc_keys {
226 ctx.decapsulate_key_unsigned(
227 AsymmetricKeyId::UserPrivateKey,
228 SymmetricKeyId::Organization(org_id),
229 &org_enc_key,
230 )?;
231 }
232
233 Ok(())
234 }
235}