1use crate::errors::*;
2use crate::KmsAeadResult;
3use rvstruct::*;
4use secret_vault_value::SecretValue;
5
6#[derive(Debug, Clone, Eq, PartialEq, ValueStruct)]
7pub struct CipherText(pub Vec<u8>);
8
9impl CipherText {
10 pub fn to_hex_string(&self) -> String {
11 hex::encode(self.value())
12 }
13}
14
15#[derive(Debug, Clone, Eq, PartialEq, ValueStruct)]
16pub struct DataEncryptionKey(pub SecretValue);
17
18#[derive(Debug, Clone, Eq, PartialEq, ValueStruct)]
19pub struct EncryptedDataEncryptionKey(pub Vec<u8>);
20
21impl EncryptedDataEncryptionKey {
22 pub fn to_hex_string(&self) -> String {
23 hex::encode(self.value())
24 }
25}
26
27#[derive(Debug, Clone, Eq, PartialEq)]
28pub struct CipherTextWithEncryptedKey(pub Vec<u8>);
29
30impl CipherTextWithEncryptedKey {
31 pub fn new(cipher_text: &CipherText, encrypted_dek: &EncryptedDataEncryptionKey) -> Self {
32 let mut value = Vec::with_capacity(
33 std::mem::size_of::<usize>() + encrypted_dek.value().len() + cipher_text.value().len(),
34 );
35 value.extend_from_slice(&encrypted_dek.value().len().to_be_bytes());
36 value.extend_from_slice(encrypted_dek.value());
37 value.extend_from_slice(cipher_text.value());
38
39 value.into()
40 }
41
42 pub fn separate(&self) -> KmsAeadResult<(CipherText, EncryptedDataEncryptionKey)> {
43 let us_len = std::mem::size_of::<usize>();
44
45 if self.value().len() < us_len {
46 return Err(KmsAeadEncryptionError::create(
47 "INVALID_CIPHER_TEXT_FORMAT",
48 "Unexpected len of cipher text to decode",
49 ));
50 }
51
52 let len_slice = &self.0.as_slice()[0..us_len];
53 let dek_len = usize::from_be_bytes(len_slice.try_into().unwrap());
54
55 if self.value().len() < us_len + dek_len {
56 return Err(KmsAeadEncryptionError::create(
57 "INVALID_CIPHER_TEXT_FORMAT",
58 "Unexpected len of cipher text to decode: DEK len is more than buffer",
59 ));
60 }
61
62 let dek: EncryptedDataEncryptionKey =
63 self.0.as_slice()[us_len..us_len + dek_len].to_vec().into();
64
65 let cipher_text: CipherText = self.0.as_slice()[us_len + dek_len..].to_vec().into();
66 Ok((cipher_text, dek))
67 }
68
69 pub fn to_hex_string(&self) -> String {
70 hex::encode(self.value())
71 }
72
73 #[inline]
74 pub fn value(&self) -> &[u8] {
75 &self.0
76 }
77}
78
79impl From<Vec<u8>> for CipherTextWithEncryptedKey {
80 fn from(value: Vec<u8>) -> Self {
81 Self(value)
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88 use proptest::prelude::*;
89
90 pub fn generate_cipher_text() -> BoxedStrategy<CipherText> {
91 ("[a-zA-Z0-9]+")
92 .prop_map(|(mock_str)| CipherText::from(mock_str.as_bytes().to_vec()))
93 .boxed()
94 }
95
96 pub fn generate_encrypted_dek() -> BoxedStrategy<EncryptedDataEncryptionKey> {
97 ("[a-zA-Z0-9]+")
98 .prop_map(|(mock_str)| EncryptedDataEncryptionKey::from(mock_str.as_bytes().to_vec()))
99 .boxed()
100 }
101
102 proptest! {
103 #[test]
104 fn cipher_text_with_key_encoding_test(mock_cipher_text in generate_cipher_text(), mock_encrypted_dek in generate_encrypted_dek()) {
105 let cipher_text_with_key = CipherTextWithEncryptedKey::new(&mock_cipher_text, &mock_encrypted_dek);
106 let (decoded_cipher_text,decoded_dek) = cipher_text_with_key.separate().unwrap();
107 assert_eq!(decoded_cipher_text, mock_cipher_text);
108 assert_eq!(decoded_dek, mock_encrypted_dek);
109 }
110 }
111}