Skip to main content

bitwarden_crypto/traits/
decryptable.rs

1use crate::{CryptoError, EncString, KeySlotId, KeySlotIds, store::KeyStoreContext};
2
3/// A decryption operation that takes the input value and decrypts it into the output value.
4/// Implementations should generally consist of calling [Decryptable::decrypt] for all the fields of
5/// the type.
6///
7/// Decrypt must decrypt the item fully, and not leave parts encrypted. That is,
8/// decrypt(K1) -> encrypt(K2) -> decrypt(K2) MUST succed.
9pub trait Decryptable<Ids: KeySlotIds, Key: KeySlotId, Output> {
10    /// Decrypts `self` into an `Output` under `key`. See the trait-level contract: the result must
11    /// contain no cipher text.
12    fn decrypt(&self, ctx: &mut KeyStoreContext<Ids>, key: Key) -> Result<Output, CryptoError>;
13}
14
15impl<Ids: KeySlotIds> Decryptable<Ids, Ids::Symmetric, Vec<u8>> for EncString {
16    #[bitwarden_logging::instrument(err)]
17    fn decrypt(
18        &self,
19        ctx: &mut KeyStoreContext<Ids>,
20        key: Ids::Symmetric,
21    ) -> Result<Vec<u8>, CryptoError> {
22        ctx.decrypt_data_with_symmetric_key(key, self)
23    }
24}
25
26impl<Ids: KeySlotIds> Decryptable<Ids, Ids::Symmetric, String> for EncString {
27    #[bitwarden_logging::instrument(err)]
28    fn decrypt(
29        &self,
30        ctx: &mut KeyStoreContext<Ids>,
31        key: Ids::Symmetric,
32    ) -> Result<String, CryptoError> {
33        let bytes: Vec<u8> = self.decrypt(ctx, key)?;
34        String::from_utf8(bytes).map_err(|_| CryptoError::InvalidUtf8String)
35    }
36}
37
38impl<Ids: KeySlotIds, Key: KeySlotId, T: Decryptable<Ids, Key, Output>, Output>
39    Decryptable<Ids, Key, Option<Output>> for Option<T>
40{
41    fn decrypt(
42        &self,
43        ctx: &mut KeyStoreContext<Ids>,
44        key: Key,
45    ) -> Result<Option<Output>, CryptoError> {
46        self.as_ref()
47            .map(|value| value.decrypt(ctx, key))
48            .transpose()
49    }
50}
51
52impl<Ids: KeySlotIds, Key: KeySlotId, T: Decryptable<Ids, Key, Output>, Output>
53    Decryptable<Ids, Key, Vec<Output>> for Vec<T>
54{
55    fn decrypt(
56        &self,
57        ctx: &mut KeyStoreContext<Ids>,
58        key: Key,
59    ) -> Result<Vec<Output>, CryptoError> {
60        self.iter().map(|value| value.decrypt(ctx, key)).collect()
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use crate::{Decryptable, EncString, KeyStore, SymmetricCryptoKey, traits::tests::*};
67
68    fn test_store() -> KeyStore<TestIds> {
69        let store = KeyStore::<TestIds>::default();
70
71        let key = SymmetricCryptoKey::try_from("sJnO8rVi0dTwND43n0T9x7665s8mVUYNAaJ4nm7gx1iia1I7947URL60nwfIHaf9QJePO4VkNN0oT9jh4iC6aA==".to_string()).unwrap();
72
73        #[allow(deprecated)]
74        store
75            .context_mut()
76            .set_symmetric_key(TestSymmKey::A(0), key.clone())
77            .unwrap();
78
79        store
80    }
81
82    #[test]
83    fn test_decryptable_bytes() {
84        let store = test_store();
85        let mut ctx = store.context();
86        let key = TestSymmKey::A(0);
87
88        let data_encrypted: EncString = "2.kTtIypq9OLzd5iMMbU11pQ==|J4i3hTtGVdg7EZ+AQv/ujg==|QJpSpotQVpIW8j8dR/8l015WJzAIxBaOmrz4Uj/V1JA=".parse().unwrap();
89
90        let data_decrypted: Vec<u8> = data_encrypted.decrypt(&mut ctx, key).unwrap();
91        assert_eq!(data_decrypted, &[1, 2, 3, 4, 5]);
92    }
93
94    #[test]
95    fn test_decryptable_string() {
96        let store = test_store();
97        let mut ctx = store.context();
98        let key = TestSymmKey::A(0);
99
100        let data_encrypted: EncString = "2.fkvl0+sL1lwtiOn1eewsvQ==|dT0TynLl8YERZ8x7dxC+DQ==|cWhiRSYHOi/AA2LiV/JBJWbO9C7pbUpOM6TMAcV47hE=".parse().unwrap();
101
102        let data_decrypted: String = data_encrypted.decrypt(&mut ctx, key).unwrap();
103        assert_eq!(data_decrypted, "Hello, World!");
104    }
105
106    #[test]
107    fn test_decryptable_option_some() {
108        let store = test_store();
109        let mut ctx = store.context();
110        let key = TestSymmKey::A(0);
111
112        let data_encrypted: EncString = "2.fkvl0+sL1lwtiOn1eewsvQ==|dT0TynLl8YERZ8x7dxC+DQ==|cWhiRSYHOi/AA2LiV/JBJWbO9C7pbUpOM6TMAcV47hE=".parse().unwrap();
113        let data_encrypted_some = Some(data_encrypted);
114
115        let string_decrypted: Option<String> = data_encrypted_some.decrypt(&mut ctx, key).unwrap();
116        assert_eq!(string_decrypted, Some("Hello, World!".to_string()));
117    }
118
119    #[test]
120    fn test_decryptable_option_none() {
121        let store = test_store();
122        let mut ctx = store.context();
123
124        let key = TestSymmKey::A(0);
125        let none_data: Option<EncString> = None;
126        let string_decrypted: Option<String> = none_data.decrypt(&mut ctx, key).unwrap();
127        assert_eq!(string_decrypted, None);
128
129        // The None implementation will not do any decrypt operations, so it won't fail even if the
130        // key doesn't exist
131        let bad_key = TestSymmKey::B((0, 1));
132        let string_decrypted_bad: Option<String> = none_data.decrypt(&mut ctx, bad_key).unwrap();
133        assert_eq!(string_decrypted_bad, None);
134    }
135}