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