1#[cfg(test)]
24mod tests;
25
26use openssl::cipher as ossl_cipher;
27use openssl::cipher_ctx::CipherCtx;
28use openssl::error::ErrorStack;
29use std::str::FromStr;
30use std::{cmp, fmt};
31use thiserror::Error;
32
33use crate::buffer::{Buffer, BufferError, BufferMut};
34use crate::svec::SecureVec;
35
36#[derive(Debug, Error)]
38pub enum CipherError {
39 #[error("invalid key")]
41 InvalidKey,
42
43 #[error("invalid iv")]
45 InvalidIv,
46
47 #[error("invalid block-size")]
50 InvalidBlockSize,
51
52 #[error("the plaintext is not trustworthy")]
57 NotTrustworthy,
58
59 #[error(transparent)]
61 OpenSSL(#[from] ErrorStack),
62}
63
64#[derive(Clone, Copy, Debug, PartialEq)]
66pub enum Cipher {
67 None,
69
70 Aes128Ctr,
72
73 Aes192Ctr,
75
76 Aes256Ctr,
78
79 Aes128Gcm,
81
82 Aes192Gcm,
84
85 Aes256Gcm,
87}
88
89impl Cipher {
90 pub fn block_size(&self) -> usize {
92 match self.to_openssl() {
93 None => 1,
94 Some(c) => c.block_size(),
95 }
96 }
97
98 pub fn key_len(&self) -> usize {
100 match self.to_openssl() {
101 None => 0,
102 Some(c) => c.key_length(),
103 }
104 }
105
106 pub fn iv_len(&self) -> usize {
108 match self.to_openssl() {
109 None => 0,
110 Some(c) => c.iv_length(),
111 }
112 }
113
114 pub fn tag_size(&self) -> u32 {
125 match self {
126 Cipher::None => 0,
127 Cipher::Aes128Ctr | Cipher::Aes192Ctr | Cipher::Aes256Ctr => 0,
128 Cipher::Aes128Gcm | Cipher::Aes192Gcm | Cipher::Aes256Gcm => 16,
129 }
130 }
131
132 pub(crate) fn get_from_buffer<T: Buffer>(buf: &mut T) -> Result<Cipher, BufferError> {
133 let b = buf.get_u32()?;
134
135 match b {
136 0 => Ok(Cipher::None),
137 1 => Ok(Cipher::Aes128Ctr),
138 2 => Ok(Cipher::Aes128Gcm),
139 3 => Ok(Cipher::Aes192Ctr),
140 4 => Ok(Cipher::Aes256Ctr),
141 5 => Ok(Cipher::Aes192Gcm),
142 6 => Ok(Cipher::Aes256Gcm),
143 _ => Err(BufferError::InvalidIndex("Cipher".to_string(), b)),
144 }
145 }
146
147 pub(crate) fn put_into_buffer<T: BufferMut>(&self, buf: &mut T) -> Result<(), BufferError> {
148 let b = match self {
149 Cipher::None => 0,
150 Cipher::Aes128Ctr => 1,
151 Cipher::Aes128Gcm => 2,
152 Cipher::Aes192Ctr => 3,
153 Cipher::Aes256Ctr => 4,
154 Cipher::Aes192Gcm => 5,
155 Cipher::Aes256Gcm => 6,
156 };
157
158 buf.put_u32(b)
159 }
160
161 fn to_openssl(self) -> Option<&'static ossl_cipher::CipherRef> {
162 match self {
163 Cipher::None => None,
164 Cipher::Aes128Ctr => Some(ossl_cipher::Cipher::aes_128_ctr()),
165 Cipher::Aes192Ctr => Some(ossl_cipher::Cipher::aes_192_ctr()),
166 Cipher::Aes256Ctr => Some(ossl_cipher::Cipher::aes_256_ctr()),
167 Cipher::Aes128Gcm => Some(ossl_cipher::Cipher::aes_128_gcm()),
168 Cipher::Aes192Gcm => Some(ossl_cipher::Cipher::aes_192_gcm()),
169 Cipher::Aes256Gcm => Some(ossl_cipher::Cipher::aes_256_gcm()),
170 }
171 }
172}
173
174impl fmt::Display for Cipher {
175 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
176 let s = match self {
177 Cipher::None => "none",
178 Cipher::Aes128Ctr => "aes128-ctr",
179 Cipher::Aes192Ctr => "aes192-ctr",
180 Cipher::Aes256Ctr => "aes256-ctr",
181 Cipher::Aes128Gcm => "aes128-gcm",
182 Cipher::Aes192Gcm => "aes192-gcm",
183 Cipher::Aes256Gcm => "aes256-gcm",
184 };
185
186 fmt.write_str(s)
187 }
188}
189
190impl FromStr for Cipher {
191 type Err = ();
192
193 fn from_str(str: &str) -> Result<Self, ()> {
194 match str {
195 "none" => Ok(Cipher::None),
196 "aes128-ctr" => Ok(Cipher::Aes128Ctr),
197 "aes192-ctr" => Ok(Cipher::Aes192Ctr),
198 "aes256-ctr" => Ok(Cipher::Aes256Ctr),
199 "aes128-gcm" => Ok(Cipher::Aes128Gcm),
200 "aes192-gcm" => Ok(Cipher::Aes192Gcm),
201 "aes256-gcm" => Ok(Cipher::Aes256Gcm),
202 _ => Err(()),
203 }
204 }
205}
206
207#[derive(Debug)]
208pub(super) struct CipherContext {
209 cipher: Cipher,
210 inp: SecureVec,
211 outp: SecureVec,
212}
213
214impl CipherContext {
215 pub(super) fn new(cipher: Cipher) -> CipherContext {
216 CipherContext {
217 cipher,
218 inp: vec![].into(),
219 outp: vec![].into(),
220 }
221 }
222
223 pub fn copy_from_slice(&mut self, buf_size: usize, buf: &[u8]) -> usize {
224 let len = cmp::min(buf_size, buf.len());
225
226 self.inp.resize(buf_size, 0);
227 self.inp[..len].copy_from_slice(&buf[..len]);
228 self.inp[len..].iter_mut().for_each(|n| *n = 0);
229
230 len
231 }
232
233 pub fn inp_mut(&mut self, buf_size: usize) -> &mut [u8] {
234 self.copy_from_slice(buf_size, &[]); &mut self.inp
237 }
238
239 pub fn encrypt(&mut self, key: &[u8], iv: &[u8]) -> Result<&[u8], CipherError> {
240 match self.cipher {
241 Cipher::None => self.make_none(),
242 _ => self.encrypt_aad(None, key, iv).map(|_| ())?,
243 };
244
245 Ok(self.outp.as_slice())
246 }
247
248 fn encrypt_aad(
249 &mut self,
250 aad: Option<&[u8]>,
251 key: &[u8],
252 iv: &[u8],
253 ) -> Result<usize, CipherError> {
254 let key = key
255 .get(..self.cipher.key_len())
256 .ok_or(CipherError::InvalidKey)?;
257 let iv = iv
258 .get(..self.cipher.iv_len())
259 .ok_or(CipherError::InvalidIv)?;
260
261 let ptext_len = self.inp.len();
265
266 let ctext_len = ptext_len;
269
270 if ptext_len == 0 {
271 return Ok(0);
272 }
273
274 if ptext_len % self.cipher.block_size() != 0 {
275 return Err(CipherError::InvalidBlockSize);
276 }
277
278 let mut ctx = CipherCtx::new()?;
279
280 ctx.encrypt_init(self.cipher.to_openssl(), Some(key), Some(iv))?;
281 ctx.set_padding(false);
282
283 if let Some(buf) = aad {
284 ctx.cipher_update(buf, None)?;
285 }
286
287 self.outp
288 .resize(ctext_len + self.cipher.tag_size() as usize, 0);
289 ctx.cipher_update(&self.inp[..ptext_len], Some(&mut self.outp[..ctext_len]))?;
290
291 if self.cipher.tag_size() > 0 {
292 ctx.cipher_final(&mut [])?;
293 ctx.tag(&mut self.outp[ctext_len..])?;
294 }
295
296 Ok(ctext_len)
297 }
298
299 pub fn decrypt(&mut self, key: &[u8], iv: &[u8]) -> Result<&[u8], CipherError> {
300 match self.cipher {
301 Cipher::None => self.make_none(),
302 _ => self.decrypt_aad(None, key, iv).map(|_| ())?,
303 }
304
305 Ok(self.outp.as_slice())
306 }
307
308 fn decrypt_aad(
309 &mut self,
310 aad: Option<&[u8]>,
311 key: &[u8],
312 iv: &[u8],
313 ) -> Result<usize, CipherError> {
314 let key = key
315 .get(..self.cipher.key_len())
316 .ok_or(CipherError::InvalidKey)?;
317 let iv = iv
318 .get(..self.cipher.iv_len())
319 .ok_or(CipherError::InvalidIv)?;
320
321 let ctext_bytes = self
323 .inp
324 .len()
325 .saturating_sub(self.cipher.tag_size() as usize);
326
327 let ptext_bytes = ctext_bytes;
330
331 if ctext_bytes == 0 {
332 return Ok(0);
333 }
334
335 if ctext_bytes % self.cipher.block_size() != 0 {
336 return Err(CipherError::InvalidBlockSize);
337 }
338
339 let mut ctx = CipherCtx::new()?;
340
341 ctx.decrypt_init(self.cipher.to_openssl(), Some(key), Some(iv))?;
342 ctx.set_padding(false);
343
344 if let Some(buf) = aad {
345 ctx.cipher_update(buf, None)?;
346 }
347
348 self.outp.resize(ptext_bytes, 0);
349 ctx.cipher_update(
350 &self.inp[..ctext_bytes],
351 Some(&mut self.outp[..ptext_bytes]),
352 )?;
353
354 if self.cipher.tag_size() > 0 {
355 ctx.set_tag(&self.inp[ctext_bytes..])?;
356 ctx.cipher_final(&mut [])
357 .map_err(|_| CipherError::NotTrustworthy)?;
358 }
359
360 Ok(ctext_bytes)
361 }
362
363 fn make_none(&mut self) {
364 self.outp.clear();
365 self.outp.extend_from_slice(&self.inp);
366 }
367}