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 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#[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}