bitwarden_crypto/traits/
decryptable.rs

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