bitwarden_crypto/traits/
decryptable.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
use crate::{store::KeyStoreContext, AsymmetricEncString, CryptoError, EncString, KeyId, KeyIds};

/// A decryption operation that takes the input value and decrypts it into the output value.
/// Implementations should generally consist of calling [Decryptable::decrypt] for all the fields of
/// the type.
pub trait Decryptable<Ids: KeyIds, Key: KeyId, Output> {
    fn decrypt(&self, ctx: &mut KeyStoreContext<Ids>, key: Key) -> Result<Output, CryptoError>;
}

impl<Ids: KeyIds> Decryptable<Ids, Ids::Symmetric, Vec<u8>> for EncString {
    fn decrypt(
        &self,
        ctx: &mut KeyStoreContext<Ids>,
        key: Ids::Symmetric,
    ) -> Result<Vec<u8>, CryptoError> {
        ctx.decrypt_data_with_symmetric_key(key, self)
    }
}

impl<Ids: KeyIds> Decryptable<Ids, Ids::Asymmetric, Vec<u8>> for AsymmetricEncString {
    fn decrypt(
        &self,
        ctx: &mut KeyStoreContext<Ids>,
        key: Ids::Asymmetric,
    ) -> Result<Vec<u8>, CryptoError> {
        ctx.decrypt_data_with_asymmetric_key(key, self)
    }
}

impl<Ids: KeyIds> Decryptable<Ids, Ids::Symmetric, String> for EncString {
    fn decrypt(
        &self,
        ctx: &mut KeyStoreContext<Ids>,
        key: Ids::Symmetric,
    ) -> Result<String, CryptoError> {
        let bytes: Vec<u8> = self.decrypt(ctx, key)?;
        String::from_utf8(bytes).map_err(|_| CryptoError::InvalidUtf8String)
    }
}

impl<Ids: KeyIds> Decryptable<Ids, Ids::Asymmetric, String> for AsymmetricEncString {
    fn decrypt(
        &self,
        ctx: &mut KeyStoreContext<Ids>,
        key: Ids::Asymmetric,
    ) -> Result<String, CryptoError> {
        let bytes: Vec<u8> = self.decrypt(ctx, key)?;
        String::from_utf8(bytes).map_err(|_| CryptoError::InvalidUtf8String)
    }
}

impl<Ids: KeyIds, Key: KeyId, T: Decryptable<Ids, Key, Output>, Output>
    Decryptable<Ids, Key, Option<Output>> for Option<T>
{
    fn decrypt(
        &self,
        ctx: &mut KeyStoreContext<Ids>,
        key: Key,
    ) -> Result<Option<Output>, CryptoError> {
        self.as_ref()
            .map(|value| value.decrypt(ctx, key))
            .transpose()
    }
}

impl<Ids: KeyIds, Key: KeyId, T: Decryptable<Ids, Key, Output>, Output>
    Decryptable<Ids, Key, Vec<Output>> for Vec<T>
{
    fn decrypt(
        &self,
        ctx: &mut KeyStoreContext<Ids>,
        key: Key,
    ) -> Result<Vec<Output>, CryptoError> {
        self.iter().map(|value| value.decrypt(ctx, key)).collect()
    }
}

#[cfg(test)]
mod tests {
    use crate::{traits::tests::*, Decryptable, EncString, KeyStore, SymmetricCryptoKey};

    fn test_store() -> KeyStore<TestIds> {
        let store = KeyStore::<TestIds>::default();

        let key = SymmetricCryptoKey::try_from("sJnO8rVi0dTwND43n0T9x7665s8mVUYNAaJ4nm7gx1iia1I7947URL60nwfIHaf9QJePO4VkNN0oT9jh4iC6aA==".to_string()).unwrap();

        #[allow(deprecated)]
        store
            .context_mut()
            .set_symmetric_key(TestSymmKey::A(0), key.clone())
            .unwrap();

        store
    }

    #[test]
    fn test_decryptable_bytes() {
        let store = test_store();
        let mut ctx = store.context();
        let key = TestSymmKey::A(0);

        let data_encrypted: EncString = "2.kTtIypq9OLzd5iMMbU11pQ==|J4i3hTtGVdg7EZ+AQv/ujg==|QJpSpotQVpIW8j8dR/8l015WJzAIxBaOmrz4Uj/V1JA=".parse().unwrap();

        let data_decrypted: Vec<u8> = data_encrypted.decrypt(&mut ctx, key).unwrap();
        assert_eq!(data_decrypted, &[1, 2, 3, 4, 5]);
    }

    #[test]
    fn test_decryptable_string() {
        let store = test_store();
        let mut ctx = store.context();
        let key = TestSymmKey::A(0);

        let data_encrypted: EncString = "2.fkvl0+sL1lwtiOn1eewsvQ==|dT0TynLl8YERZ8x7dxC+DQ==|cWhiRSYHOi/AA2LiV/JBJWbO9C7pbUpOM6TMAcV47hE=".parse().unwrap();

        let data_decrypted: String = data_encrypted.decrypt(&mut ctx, key).unwrap();
        assert_eq!(data_decrypted, "Hello, World!");
    }

    #[test]
    fn test_decryptable_option_some() {
        let store = test_store();
        let mut ctx = store.context();
        let key = TestSymmKey::A(0);

        let data_encrypted: EncString = "2.fkvl0+sL1lwtiOn1eewsvQ==|dT0TynLl8YERZ8x7dxC+DQ==|cWhiRSYHOi/AA2LiV/JBJWbO9C7pbUpOM6TMAcV47hE=".parse().unwrap();
        let data_encrypted_some = Some(data_encrypted);

        let string_decrypted: Option<String> = data_encrypted_some.decrypt(&mut ctx, key).unwrap();
        assert_eq!(string_decrypted, Some("Hello, World!".to_string()));
    }

    #[test]
    fn test_decryptable_option_none() {
        let store = test_store();
        let mut ctx = store.context();

        let key = TestSymmKey::A(0);
        let none_data: Option<EncString> = None;
        let string_decrypted: Option<String> = none_data.decrypt(&mut ctx, key).unwrap();
        assert_eq!(string_decrypted, None);

        // The None implementation will not do any decrypt operations, so it won't fail even if the
        // key doesn't exist
        let bad_key = TestSymmKey::B((0, 1));
        let string_decrypted_bad: Option<String> = none_data.decrypt(&mut ctx, bad_key).unwrap();
        assert_eq!(string_decrypted_bad, None);
    }
}