bitwarden_core/key_management/
local_user_data_key.rs1use bitwarden_crypto::{EncString, KeyStoreContext};
2use key_management::LocalUserDataKeyState;
3use thiserror::Error;
4use tracing::instrument;
5
6use crate::{
7 key_management,
8 key_management::{KeyIds, SymmetricKeyId},
9};
10
11#[derive(Debug, Clone)]
15pub(crate) struct WrappedLocalUserDataKey(pub(crate) EncString);
16
17impl WrappedLocalUserDataKey {
18 #[instrument(skip(ctx), err)]
20 pub(crate) fn from_context_user_key(
21 ctx: &mut KeyStoreContext<KeyIds>,
22 ) -> Result<Self, LocalUserDataKeyError> {
23 let wrapped_local_user_data_key = ctx
24 .wrap_symmetric_key(SymmetricKeyId::User, SymmetricKeyId::User)
25 .map_err(|_| LocalUserDataKeyError::EncryptionFailed)?;
26 Ok(WrappedLocalUserDataKey(wrapped_local_user_data_key))
27 }
28
29 #[instrument(skip(self, ctx), err)]
32 pub(crate) fn unwrap_to_context(
33 &self,
34 ctx: &mut KeyStoreContext<KeyIds>,
35 ) -> Result<(), LocalUserDataKeyError> {
36 let local_id = ctx
37 .unwrap_symmetric_key(SymmetricKeyId::User, &self.0)
38 .map_err(|_| LocalUserDataKeyError::DecryptionFailed)?;
39 ctx.persist_symmetric_key(local_id, SymmetricKeyId::LocalUserData)
40 .map_err(|_| LocalUserDataKeyError::DecryptionFailed)?;
41 Ok(())
42 }
43}
44
45#[derive(Debug, Error)]
47pub enum LocalUserDataKeyError {
48 #[error("Decryption failed")]
50 DecryptionFailed,
51 #[error("Encryption failed")]
53 EncryptionFailed,
54}
55
56impl From<WrappedLocalUserDataKey> for LocalUserDataKeyState {
57 fn from(wrapped_key: WrappedLocalUserDataKey) -> Self {
58 Self {
59 wrapped_key: wrapped_key.0,
60 }
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use bitwarden_crypto::{Decryptable, KeyStore, PrimitiveEncryptable};
67
68 use super::*;
69 use crate::key_management::{KeyIds, SymmetricKeyId};
70
71 fn make_key_store_with_user_key() -> KeyStore<KeyIds> {
72 let key_store = KeyStore::<KeyIds>::default();
73 let mut ctx = key_store.context_mut();
74 let user_key = ctx.generate_symmetric_key();
75 ctx.persist_symmetric_key(user_key, SymmetricKeyId::User)
76 .expect("persisting user key should succeed");
77 drop(ctx);
78 key_store
79 }
80
81 #[test]
82 fn test_from_context_user_key_wraps_user_key() {
83 let key_store = make_key_store_with_user_key();
84 let mut ctx = key_store.context_mut();
85
86 let plaintext = "test data";
87 let ciphertext = plaintext
88 .encrypt(&mut ctx, SymmetricKeyId::User)
89 .expect("encryption with user key should succeed");
90
91 let wrapped = WrappedLocalUserDataKey::from_context_user_key(&mut ctx)
92 .expect("wrapping should succeed");
93 wrapped
94 .unwrap_to_context(&mut ctx)
95 .expect("unwrapping should succeed");
96
97 let decrypted: String = ciphertext
100 .decrypt(&mut ctx, SymmetricKeyId::LocalUserData)
101 .expect("decryption with local user data key should succeed");
102 assert_eq!(decrypted, plaintext);
103 }
104
105 #[test]
106 fn test_unwrap_to_context_fails_with_wrong_key() {
107 let key_store_a = make_key_store_with_user_key();
108 let wrapped = {
109 let mut ctx = key_store_a.context_mut();
110 WrappedLocalUserDataKey::from_context_user_key(&mut ctx)
111 .expect("wrapping should succeed")
112 };
113
114 let key_store_b = make_key_store_with_user_key();
115 let mut ctx_b = key_store_b.context_mut();
116 assert!(
117 wrapped.unwrap_to_context(&mut ctx_b).is_err(),
118 "unwrapping with a different key should fail"
119 );
120 }
121}