kms_aead/
ring_encryption.rs

1use crate::ring_support::*;
2use crate::{AeadEncryption, CipherText, DataEncryptionKey, KmsAeadResult};
3use async_trait::*;
4use ring::rand::SystemRandom;
5use rsb_derive::*;
6use rvstruct::ValueStruct;
7use secret_vault_value::SecretValue;
8
9#[derive(Debug, Clone, Builder)]
10pub struct RingAeadEncryptionOptions {
11    #[default = "RingAeadEncryptionNonceKind::TimeRandom"]
12    pub nonce_kind: RingAeadEncryptionNonceKind,
13}
14
15#[derive(Debug, Clone)]
16pub enum RingAeadEncryptionNonceKind {
17    Random,
18    TimeRandom,
19}
20
21pub struct RingAeadEncryption {
22    pub algo: &'static ring::aead::Algorithm,
23    secure_rand: SystemRandom,
24    pub options: RingAeadEncryptionOptions,
25}
26
27impl RingAeadEncryption {
28    pub fn new() -> KmsAeadResult<Self> {
29        Self::with_rand(SystemRandom::new())
30    }
31
32    pub fn with_rand(secure_rand: SystemRandom) -> KmsAeadResult<Self> {
33        Self::with_algorithm(&ring::aead::CHACHA20_POLY1305, secure_rand)
34    }
35
36    pub fn with_algorithm(
37        algo: &'static ring::aead::Algorithm,
38        secure_rand: SystemRandom,
39    ) -> KmsAeadResult<Self> {
40        Self::with_algorithm_options(algo, secure_rand, RingAeadEncryptionOptions::new())
41    }
42
43    pub fn with_options(
44        secure_rand: SystemRandom,
45        options: RingAeadEncryptionOptions,
46    ) -> KmsAeadResult<Self> {
47        Self::with_algorithm_options(&ring::aead::CHACHA20_POLY1305, secure_rand, options)
48    }
49
50    pub fn with_algorithm_options(
51        algo: &'static ring::aead::Algorithm,
52        secure_rand: SystemRandom,
53        options: RingAeadEncryptionOptions,
54    ) -> KmsAeadResult<Self> {
55        Ok(Self {
56            algo,
57            secure_rand,
58            options,
59        })
60    }
61
62    pub fn generate_data_encryption_key(&self) -> KmsAeadResult<DataEncryptionKey> {
63        generate_secret_key(&self.secure_rand, self.algo.key_len())
64    }
65}
66
67#[async_trait]
68impl<Aad> AeadEncryption<Aad> for RingAeadEncryption
69where
70    Aad: AsRef<[u8]> + Send + Sync + 'static,
71{
72    async fn encrypt_value(
73        &self,
74        aad: &Aad,
75        plain_text: &SecretValue,
76        encryption_key: &DataEncryptionKey,
77    ) -> KmsAeadResult<CipherText> {
78        let nonce_data = match self.options.nonce_kind {
79            RingAeadEncryptionNonceKind::Random => generate_random_nonce(&self.secure_rand)?,
80            RingAeadEncryptionNonceKind::TimeRandom => {
81                generate_time_random_nonce(&self.secure_rand)?
82            }
83        };
84
85        let encrypted_value = encrypt_with_sealing_key(
86            self.algo,
87            encryption_key,
88            nonce_data.as_slice(),
89            ring::aead::Aad::from(aad),
90            plain_text.ref_sensitive_value().as_slice(),
91        )?;
92
93        let mut encrypted_value_with_nonce: Vec<u8> =
94            Vec::with_capacity(nonce_data.len() + encrypted_value.value().len());
95
96        encrypted_value_with_nonce.extend_from_slice(nonce_data.as_slice());
97
98        encrypted_value_with_nonce.extend_from_slice(encrypted_value.value().as_slice());
99
100        Ok(CipherText(encrypted_value_with_nonce))
101    }
102
103    async fn decrypt_value(
104        &self,
105        aad: &Aad,
106        cipher_text: &CipherText,
107        encryption_key: &DataEncryptionKey,
108    ) -> KmsAeadResult<SecretValue> {
109        let (nonce_data, encrypted_part) = cipher_text.value().split_at(ring::aead::NONCE_LEN);
110
111        decrypt_with_opening_key(
112            self.algo,
113            encryption_key,
114            nonce_data,
115            ring::aead::Aad::from(aad),
116            encrypted_part,
117        )
118    }
119}
120
121#[cfg(test)]
122mod tests {
123    use super::*;
124    use proptest::prelude::*;
125    use proptest::strategy::ValueTree;
126    use proptest::test_runner::TestRunner;
127
128    pub fn generate_secret_value() -> BoxedStrategy<SecretValue> {
129        ("[a-zA-Z0-9]+")
130            .prop_map(|(mock_secret_str)| SecretValue::new(mock_secret_str.as_bytes().to_vec()))
131            .boxed()
132    }
133
134    async fn encryption_test_for(mock_secret_value: SecretValue) {
135        let mock_aad: String = "test".to_string();
136        let secure_rand: SystemRandom = SystemRandom::new();
137
138        let encryption = RingAeadEncryption::with_rand(secure_rand).unwrap();
139
140        let secret_key = encryption.generate_data_encryption_key().unwrap();
141
142        let encrypted_value = encryption
143            .encrypt_value(&mock_aad, &mock_secret_value, &secret_key)
144            .await
145            .unwrap();
146
147        assert_ne!(
148            encrypted_value.value(),
149            mock_secret_value.ref_sensitive_value()
150        );
151
152        let decrypted_value = encryption
153            .decrypt_value(&mock_aad, &encrypted_value, &secret_key)
154            .await
155            .unwrap();
156        assert_eq!(
157            decrypted_value.ref_sensitive_value(),
158            mock_secret_value.ref_sensitive_value()
159        );
160    }
161
162    #[tokio::test]
163    async fn secret_encryption_test() {
164        let mut runner = TestRunner::default();
165        encryption_test_for(
166            generate_secret_value()
167                .new_tree(&mut runner)
168                .unwrap()
169                .current(),
170        )
171        .await
172    }
173
174    #[tokio::test]
175    async fn big_secret_encryption_test() {
176        for sz in vec![5000, 32768, 65535] {
177            encryption_test_for(SecretValue::new("42".repeat(sz).as_bytes().to_vec())).await
178        }
179    }
180
181    #[tokio::test]
182    async fn wrong_secret_name_test_attest() {
183        let mock_aad1: String = "test1".to_string();
184        let mock_aad2: String = "test2".to_string();
185
186        let mock_secret_value = SecretValue::new("42".repeat(1024).as_bytes().to_vec());
187
188        let secure_rand: SystemRandom = SystemRandom::new();
189
190        let encryption = RingAeadEncryption::with_rand(secure_rand).unwrap();
191
192        let secret_key = encryption.generate_data_encryption_key().unwrap();
193
194        let encrypted_value = encryption
195            .encrypt_value(&mock_aad1, &mock_secret_value, &secret_key)
196            .await
197            .unwrap();
198        encryption
199            .decrypt_value(&mock_aad2, &encrypted_value, &secret_key)
200            .await
201            .expect_err("Unable to decrypt data");
202    }
203
204    #[tokio::test]
205    async fn different_encryption_instances_test() {
206        let mock_aad: String = "test1".to_string();
207        let mock_secret_value = SecretValue::new("42".repeat(1024).as_bytes().to_vec());
208
209        let secure_rand: SystemRandom = SystemRandom::new();
210
211        let secret_key =
212            generate_secret_key(&secure_rand, ring::aead::CHACHA20_POLY1305.key_len()).unwrap();
213
214        let encrypted_value = {
215            let encryption = RingAeadEncryption::with_rand(secure_rand.clone()).unwrap();
216            encryption
217                .encrypt_value(&mock_aad, &mock_secret_value, &secret_key)
218                .await
219                .unwrap()
220        };
221
222        let decrypted_value = {
223            let encryption = RingAeadEncryption::with_rand(secure_rand.clone()).unwrap();
224            encryption
225                .decrypt_value(&mock_aad, &encrypted_value, &secret_key)
226                .await
227                .unwrap()
228        };
229
230        assert_eq!(decrypted_value, mock_secret_value)
231    }
232}