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::Random"]
12 pub nonce_kind: RingAeadEncryptionNonceKind,
13}
14
15#[derive(Debug, Clone)]
16pub enum RingAeadEncryptionNonceKind {
17 Random,
18}
19
20pub struct RingAeadEncryption {
21 pub algo: &'static ring::aead::Algorithm,
22 secure_rand: SystemRandom,
23 pub options: RingAeadEncryptionOptions,
24}
25
26impl RingAeadEncryption {
27 pub fn new() -> KmsAeadResult<Self> {
28 Self::with_rand(SystemRandom::new())
29 }
30
31 pub fn with_rand(secure_rand: SystemRandom) -> KmsAeadResult<Self> {
32 Self::with_algorithm(&ring::aead::CHACHA20_POLY1305, secure_rand)
33 }
34
35 pub fn with_algorithm(
36 algo: &'static ring::aead::Algorithm,
37 secure_rand: SystemRandom,
38 ) -> KmsAeadResult<Self> {
39 Self::with_algorithm_options(algo, secure_rand, RingAeadEncryptionOptions::new())
40 }
41
42 pub fn with_options(
43 secure_rand: SystemRandom,
44 options: RingAeadEncryptionOptions,
45 ) -> KmsAeadResult<Self> {
46 Self::with_algorithm_options(&ring::aead::CHACHA20_POLY1305, secure_rand, options)
47 }
48
49 pub fn with_algorithm_options(
50 algo: &'static ring::aead::Algorithm,
51 secure_rand: SystemRandom,
52 options: RingAeadEncryptionOptions,
53 ) -> KmsAeadResult<Self> {
54 Ok(Self {
55 algo,
56 secure_rand,
57 options,
58 })
59 }
60
61 pub fn generate_data_encryption_key(&self) -> KmsAeadResult<DataEncryptionKey> {
62 generate_secret_key(&self.secure_rand, self.algo.key_len())
63 }
64}
65
66#[async_trait]
67impl<Aad> AeadEncryption<Aad> for RingAeadEncryption
68where
69 Aad: AsRef<[u8]> + Send + Sync + 'static,
70{
71 async fn encrypt_value(
72 &self,
73 aad: &Aad,
74 plain_text: &SecretValue,
75 encryption_key: &DataEncryptionKey,
76 ) -> KmsAeadResult<CipherText> {
77 let nonce_data = match self.options.nonce_kind {
78 RingAeadEncryptionNonceKind::Random => generate_random_nonce(&self.secure_rand)?,
79 };
80
81 let encrypted_value = encrypt_with_sealing_key(
82 self.algo,
83 encryption_key,
84 nonce_data.as_slice(),
85 ring::aead::Aad::from(aad),
86 plain_text.ref_sensitive_value().as_slice(),
87 )?;
88
89 let mut encrypted_value_with_nonce: Vec<u8> =
90 Vec::with_capacity(nonce_data.len() + encrypted_value.value().len());
91
92 encrypted_value_with_nonce.extend_from_slice(nonce_data.as_slice());
93
94 encrypted_value_with_nonce.extend_from_slice(encrypted_value.value().as_slice());
95
96 Ok(CipherText(encrypted_value_with_nonce))
97 }
98
99 async fn decrypt_value(
100 &self,
101 aad: &Aad,
102 cipher_text: &CipherText,
103 encryption_key: &DataEncryptionKey,
104 ) -> KmsAeadResult<SecretValue> {
105 if cipher_text.value().len() < ring::aead::NONCE_LEN {
106 return Err(crate::errors::KmsAeadEncryptionError::create(
107 "INVALID_CIPHERTEXT",
108 "Ciphertext too short to contain nonce",
109 ));
110 }
111
112 let (nonce_data, encrypted_part) = cipher_text.value().split_at(ring::aead::NONCE_LEN);
113
114 decrypt_with_opening_key(
115 self.algo,
116 encryption_key,
117 nonce_data,
118 ring::aead::Aad::from(aad),
119 encrypted_part,
120 )
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127 use crate::types::{CipherText, DataEncryptionKey};
128 use proptest::prelude::*;
129 use proptest::strategy::ValueTree;
130 use proptest::test_runner::TestRunner;
131
132 pub fn generate_secret_value() -> BoxedStrategy<SecretValue> {
133 ("[a-zA-Z0-9]+")
134 .prop_map(|(mock_secret_str)| SecretValue::new(mock_secret_str.as_bytes().to_vec()))
135 .boxed()
136 }
137
138 async fn encryption_test_for(mock_secret_value: SecretValue) {
139 let mock_aad: String = "test".to_string();
140 let secure_rand: SystemRandom = SystemRandom::new();
141
142 let encryption = RingAeadEncryption::with_rand(secure_rand).unwrap();
143
144 let secret_key = encryption.generate_data_encryption_key().unwrap();
145
146 let encrypted_value = encryption
147 .encrypt_value(&mock_aad, &mock_secret_value, &secret_key)
148 .await
149 .unwrap();
150
151 assert_ne!(
152 encrypted_value.value(),
153 mock_secret_value.ref_sensitive_value()
154 );
155
156 let decrypted_value = encryption
157 .decrypt_value(&mock_aad, &encrypted_value, &secret_key)
158 .await
159 .unwrap();
160 assert_eq!(
161 decrypted_value.ref_sensitive_value(),
162 mock_secret_value.ref_sensitive_value()
163 );
164 }
165
166 #[tokio::test]
167 async fn secret_encryption_test() {
168 let mut runner = TestRunner::default();
169 encryption_test_for(
170 generate_secret_value()
171 .new_tree(&mut runner)
172 .unwrap()
173 .current(),
174 )
175 .await
176 }
177
178 #[tokio::test]
179 async fn big_secret_encryption_test() {
180 for sz in vec![5000, 32768, 65535] {
181 encryption_test_for(SecretValue::new("42".repeat(sz).as_bytes().to_vec())).await
182 }
183 }
184
185 #[tokio::test]
186 async fn wrong_secret_name_test_attest() {
187 let mock_aad1: String = "test1".to_string();
188 let mock_aad2: String = "test2".to_string();
189
190 let mock_secret_value = SecretValue::new("42".repeat(1024).as_bytes().to_vec());
191
192 let secure_rand: SystemRandom = SystemRandom::new();
193
194 let encryption = RingAeadEncryption::with_rand(secure_rand).unwrap();
195
196 let secret_key = encryption.generate_data_encryption_key().unwrap();
197
198 let encrypted_value = encryption
199 .encrypt_value(&mock_aad1, &mock_secret_value, &secret_key)
200 .await
201 .unwrap();
202 encryption
203 .decrypt_value(&mock_aad2, &encrypted_value, &secret_key)
204 .await
205 .expect_err("Unable to decrypt data");
206 }
207
208 #[tokio::test]
209 async fn different_encryption_instances_test() {
210 let mock_aad: String = "test1".to_string();
211 let mock_secret_value = SecretValue::new("42".repeat(1024).as_bytes().to_vec());
212
213 let secure_rand: SystemRandom = SystemRandom::new();
214
215 let secret_key =
216 generate_secret_key(&secure_rand, ring::aead::CHACHA20_POLY1305.key_len()).unwrap();
217
218 let encrypted_value = {
219 let encryption = RingAeadEncryption::with_rand(secure_rand.clone()).unwrap();
220 encryption
221 .encrypt_value(&mock_aad, &mock_secret_value, &secret_key)
222 .await
223 .unwrap()
224 };
225
226 let decrypted_value = {
227 let encryption = RingAeadEncryption::with_rand(secure_rand.clone()).unwrap();
228 encryption
229 .decrypt_value(&mock_aad, &encrypted_value, &secret_key)
230 .await
231 .unwrap()
232 };
233
234 assert_eq!(decrypted_value, mock_secret_value)
235 }
236
237 #[tokio::test]
238 async fn empty_plaintext_test() {
239 let mock_aad: String = "test-aad".to_string();
240 let secure_rand: SystemRandom = SystemRandom::new();
241
242 let encryption = RingAeadEncryption::with_rand(secure_rand).unwrap();
243 let secret_key = encryption.generate_data_encryption_key().unwrap();
244
245 let empty_secret = SecretValue::new(Vec::new());
246
247 let encrypted_value = encryption
248 .encrypt_value(&mock_aad, &empty_secret, &secret_key)
249 .await
250 .unwrap();
251
252 let decrypted_value = encryption
253 .decrypt_value(&mock_aad, &encrypted_value, &secret_key)
254 .await
255 .unwrap();
256
257 assert_eq!(decrypted_value.ref_sensitive_value().len(), 0);
258 }
259
260 #[tokio::test]
261 async fn empty_aad_test() {
262 let empty_aad = b"";
263 let secure_rand: SystemRandom = SystemRandom::new();
264
265 let encryption = RingAeadEncryption::with_rand(secure_rand).unwrap();
266 let secret_key = encryption.generate_data_encryption_key().unwrap();
267
268 let secret = SecretValue::new("test-secret".as_bytes().to_vec());
269
270 let encrypted_value = encryption
271 .encrypt_value(&empty_aad, &secret, &secret_key)
272 .await
273 .unwrap();
274
275 let decrypted_value = encryption
276 .decrypt_value(&empty_aad, &encrypted_value, &secret_key)
277 .await
278 .unwrap();
279
280 assert_eq!(decrypted_value, secret);
281 }
282
283 #[tokio::test]
284 async fn binary_aad_test() {
285 let binary_aad: Vec<u8> = vec![0x00, 0xFF, 0xDE, 0xAD, 0xBE, 0xEF, 0x00];
287 let secure_rand: SystemRandom = SystemRandom::new();
288
289 let encryption = RingAeadEncryption::with_rand(secure_rand).unwrap();
290 let secret_key = encryption.generate_data_encryption_key().unwrap();
291
292 let secret = SecretValue::new("test-secret".as_bytes().to_vec());
293
294 let encrypted_value = encryption
295 .encrypt_value(&binary_aad, &secret, &secret_key)
296 .await
297 .unwrap();
298
299 let decrypted_value = encryption
300 .decrypt_value(&binary_aad, &encrypted_value, &secret_key)
301 .await
302 .unwrap();
303
304 assert_eq!(decrypted_value, secret);
305 }
306
307 #[tokio::test]
308 async fn wrong_key_decryption_fails() {
309 let mock_aad: String = "test-aad".to_string();
310 let secure_rand: SystemRandom = SystemRandom::new();
311
312 let encryption = RingAeadEncryption::with_rand(secure_rand.clone()).unwrap();
313 let secret_key1 = encryption.generate_data_encryption_key().unwrap();
314 let secret_key2 = encryption.generate_data_encryption_key().unwrap();
315
316 let secret = SecretValue::new("test-secret".as_bytes().to_vec());
317
318 let encrypted_value = encryption
319 .encrypt_value(&mock_aad, &secret, &secret_key1)
320 .await
321 .unwrap();
322
323 let result = encryption
325 .decrypt_value(&mock_aad, &encrypted_value, &secret_key2)
326 .await;
327
328 assert!(result.is_err(), "Decryption with wrong key should fail");
329 }
330
331 #[tokio::test]
332 async fn truncated_ciphertext_fails() {
333 let mock_aad: String = "test-aad".to_string();
334 let secure_rand: SystemRandom = SystemRandom::new();
335
336 let encryption = RingAeadEncryption::with_rand(secure_rand).unwrap();
337 let secret_key = encryption.generate_data_encryption_key().unwrap();
338
339 let secret = SecretValue::new("test-secret".as_bytes().to_vec());
340
341 let encrypted_value = encryption
342 .encrypt_value(&mock_aad, &secret, &secret_key)
343 .await
344 .unwrap();
345
346 let mut truncated = encrypted_value.value().to_vec();
348 truncated.truncate(truncated.len() - 5);
349 let truncated_cipher = CipherText(truncated);
350
351 let result = encryption
352 .decrypt_value(&mock_aad, &truncated_cipher, &secret_key)
353 .await;
354
355 assert!(
356 result.is_err(),
357 "Decryption of truncated ciphertext should fail"
358 );
359 }
360
361 #[tokio::test]
362 async fn modified_ciphertext_fails() {
363 let mock_aad: String = "test-aad".to_string();
364 let secure_rand: SystemRandom = SystemRandom::new();
365
366 let encryption = RingAeadEncryption::with_rand(secure_rand).unwrap();
367 let secret_key = encryption.generate_data_encryption_key().unwrap();
368
369 let secret = SecretValue::new("test-secret".as_bytes().to_vec());
370
371 let encrypted_value = encryption
372 .encrypt_value(&mock_aad, &secret, &secret_key)
373 .await
374 .unwrap();
375
376 let mut modified = encrypted_value.value().to_vec();
378 if modified.len() > ring::aead::NONCE_LEN + 1 {
379 modified[ring::aead::NONCE_LEN + 1] ^= 0x01;
380 }
381 let modified_cipher = CipherText(modified);
382
383 let result = encryption
384 .decrypt_value(&mock_aad, &modified_cipher, &secret_key)
385 .await;
386
387 assert!(
388 result.is_err(),
389 "Decryption of modified ciphertext should fail"
390 );
391 }
392
393 #[tokio::test]
394 async fn modified_nonce_fails() {
395 let mock_aad: String = "test-aad".to_string();
396 let secure_rand: SystemRandom = SystemRandom::new();
397
398 let encryption = RingAeadEncryption::with_rand(secure_rand).unwrap();
399 let secret_key = encryption.generate_data_encryption_key().unwrap();
400
401 let secret = SecretValue::new("test-secret".as_bytes().to_vec());
402
403 let encrypted_value = encryption
404 .encrypt_value(&mock_aad, &secret, &secret_key)
405 .await
406 .unwrap();
407
408 let mut modified = encrypted_value.value().to_vec();
410 modified[0] ^= 0x01;
411 let modified_cipher = CipherText(modified);
412
413 let result = encryption
414 .decrypt_value(&mock_aad, &modified_cipher, &secret_key)
415 .await;
416
417 assert!(
418 result.is_err(),
419 "Decryption with modified nonce should fail"
420 );
421 }
422
423 #[tokio::test]
424 async fn too_short_ciphertext_fails() {
425 let mock_aad: String = "test-aad".to_string();
426 let secure_rand: SystemRandom = SystemRandom::new();
427
428 let encryption = RingAeadEncryption::with_rand(secure_rand).unwrap();
429 let secret_key = encryption.generate_data_encryption_key().unwrap();
430
431 let short_cipher = CipherText(vec![0u8; ring::aead::NONCE_LEN - 1]);
433
434 let result = encryption
435 .decrypt_value(&mock_aad, &short_cipher, &secret_key)
436 .await;
437
438 assert!(
439 result.is_err(),
440 "Decryption of too-short ciphertext should fail"
441 );
442 }
443
444 #[tokio::test]
445 async fn test_aes_256_gcm_algorithm() {
446 let mock_aad: String = "test-aad".to_string();
447 let secure_rand: SystemRandom = SystemRandom::new();
448
449 let encryption =
450 RingAeadEncryption::with_algorithm(&ring::aead::AES_256_GCM, secure_rand).unwrap();
451
452 let secret_key = encryption.generate_data_encryption_key().unwrap();
453 let secret = SecretValue::new("test-secret".as_bytes().to_vec());
454
455 let encrypted_value = encryption
456 .encrypt_value(&mock_aad, &secret, &secret_key)
457 .await
458 .unwrap();
459
460 let decrypted_value = encryption
461 .decrypt_value(&mock_aad, &encrypted_value, &secret_key)
462 .await
463 .unwrap();
464
465 assert_eq!(decrypted_value, secret);
466 }
467
468 #[test]
469 fn test_constant_time_cipher_text_comparison() {
470 let cipher1 = CipherText(vec![1, 2, 3, 4, 5]);
471 let cipher2 = CipherText(vec![1, 2, 3, 4, 5]);
472 let cipher3 = CipherText(vec![1, 2, 3, 4, 6]);
473
474 assert_eq!(cipher1, cipher2);
476 assert_ne!(cipher1, cipher3);
477 }
478
479 #[test]
480 fn test_constant_time_dek_comparison() {
481 let dek1 = DataEncryptionKey::from(SecretValue::new(vec![1, 2, 3, 4, 5]));
482 let dek2 = DataEncryptionKey::from(SecretValue::new(vec![1, 2, 3, 4, 5]));
483 let dek3 = DataEncryptionKey::from(SecretValue::new(vec![1, 2, 3, 4, 6]));
484
485 assert_eq!(dek1, dek2);
487 assert_ne!(dek1, dek3);
488 }
489
490 #[tokio::test]
491 async fn concurrent_encryption_test() {
492 use tokio::task;
493
494 let secure_rand: SystemRandom = SystemRandom::new();
495 let encryption = RingAeadEncryption::with_rand(secure_rand).unwrap();
496 let secret_key = encryption.generate_data_encryption_key().unwrap();
497
498 let mut handles = vec![];
499 for i in 0..10 {
500 let encryption_clone = RingAeadEncryption::with_rand(SystemRandom::new()).unwrap();
501 let key_clone = secret_key.clone();
502 let handle = task::spawn(async move {
503 let secret = SecretValue::new(format!("secret-{}", i).as_bytes().to_vec());
504 let aad = format!("aad-{}", i);
505
506 let encrypted = encryption_clone
507 .encrypt_value(&aad, &secret, &key_clone)
508 .await
509 .unwrap();
510
511 let decrypted = encryption_clone
512 .decrypt_value(&aad, &encrypted, &key_clone)
513 .await
514 .unwrap();
515
516 assert_eq!(decrypted, secret);
517 });
518 handles.push(handle);
519 }
520
521 for handle in handles {
522 handle.await.unwrap();
523 }
524 }
525}