Skip to main content

vitaminc_aead/
encrypt.rs

1use crate::{
2    aad::IntoAad,
3    cipher::{Cipher, Unspecified},
4    LocalCipherText,
5};
6use vitaminc_protected::{Controlled, Protected};
7use zeroize::Zeroize;
8
9pub trait Encrypt<'a>: Sized + 'a {
10    type Encrypted;
11
12    fn encrypt<C>(self, cipher: &C) -> Result<Self::Encrypted, Unspecified>
13    where
14        C: Cipher,
15    {
16        self.encrypt_with_aad(cipher, ())
17    }
18
19    fn encrypt_with_aad<C, A>(self, cipher: &C, aad: A) -> Result<Self::Encrypted, Unspecified>
20    where
21        C: Cipher,
22        A: IntoAad<'a>;
23}
24
25impl<'a> Encrypt<'a> for Vec<u8> {
26    type Encrypted = LocalCipherText;
27
28    fn encrypt_with_aad<C, A>(self, cipher: &C, aad: A) -> Result<Self::Encrypted, Unspecified>
29    where
30        C: Cipher,
31        A: IntoAad<'a>,
32    {
33        cipher.encrypt_vec(self, aad)
34    }
35}
36
37impl<'a> Encrypt<'a> for String {
38    type Encrypted = LocalCipherText;
39
40    fn encrypt_with_aad<C, A>(self, cipher: &C, aad: A) -> Result<Self::Encrypted, Unspecified>
41    where
42        C: Cipher,
43        A: IntoAad<'a>,
44    {
45        cipher.encrypt_vec(self.into_bytes(), aad)
46    }
47}
48
49impl<'a> Encrypt<'a> for &'a str {
50    type Encrypted = LocalCipherText;
51
52    fn encrypt_with_aad<C, A>(self, cipher: &C, aad: A) -> Result<Self::Encrypted, Unspecified>
53    where
54        C: Cipher,
55        A: IntoAad<'a>,
56    {
57        cipher.encrypt_slice(self.as_bytes(), aad)
58    }
59}
60
61impl<'a, const N: usize> Encrypt<'a> for [u8; N] {
62    type Encrypted = LocalCipherText;
63
64    fn encrypt_with_aad<C, A>(mut self, cipher: &C, aad: A) -> Result<Self::Encrypted, Unspecified>
65    where
66        C: Cipher,
67        A: IntoAad<'a>,
68    {
69        let bytes = self.to_vec();
70        let result = cipher.encrypt_vec(bytes, aad);
71        // `to_vec` copies the bytes, do we must zeroize the original
72        self.zeroize();
73        result
74    }
75}
76
77impl<'a, T> Encrypt<'a> for Protected<T>
78where
79    Self: Controlled + 'a,
80    <Protected<T> as Controlled>::Inner: Encrypt<'a>,
81{
82    type Encrypted = <<Protected<T> as Controlled>::Inner as Encrypt<'a>>::Encrypted;
83
84    fn encrypt_with_aad<C, A>(self, cipher: &C, aad: A) -> Result<Self::Encrypted, Unspecified>
85    where
86        C: Cipher,
87        A: IntoAad<'a>,
88    {
89        self.risky_unwrap().encrypt_with_aad(cipher, aad)
90    }
91}
92
93// FIXME: check with @coderdan if this should be converted to a static assertion that it simply *compiles*
94#[allow(dead_code)]
95#[cfg(test)]
96mod tests {
97    use super::*;
98    use crate::Decrypt;
99
100    struct Foo {
101        sensitive: String,
102        public: String,
103    }
104
105    struct EncryptedFoo {
106        sensitive: LocalCipherText,
107        public: String,
108    }
109
110    impl<'a> Encrypt<'a> for Foo {
111        type Encrypted = EncryptedFoo;
112
113        fn encrypt_with_aad<C, A>(self, cipher: &C, aad: A) -> Result<Self::Encrypted, Unspecified>
114        where
115            C: Cipher,
116            A: IntoAad<'a>,
117        {
118            let sensitive = self.sensitive.encrypt_with_aad(cipher, aad)?;
119            Ok(EncryptedFoo {
120                sensitive,
121                public: self.public,
122            })
123        }
124    }
125
126    impl Decrypt for Foo {
127        type Encrypted = EncryptedFoo;
128
129        fn decrypt_with_aad<'a, C, A>(
130            encrypted: Self::Encrypted,
131            cipher: &C,
132            aad: A,
133        ) -> Result<Self, Unspecified>
134        where
135            C: Cipher,
136            A: IntoAad<'a>,
137        {
138            String::decrypt_with_aad(encrypted.sensitive, cipher, aad).map(|sensitive| Foo {
139                sensitive,
140                public: encrypted.public,
141            })
142        }
143    }
144}