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