Skip to main content

kms_aead/
types.rs

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}