• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! The symmetric encryption context.
2 //!
3 //! # Examples
4 //!
5 //! Encrypt data with AES128 CBC
6 //!
7 //! ```
8 //! use openssl::cipher::Cipher;
9 //! use openssl::cipher_ctx::CipherCtx;
10 //!
11 //! let cipher = Cipher::aes_128_cbc();
12 //! let data = b"Some Crypto Text";
13 //! let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F";
14 //! let iv = b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07";
15 //!
16 //! let mut ctx = CipherCtx::new().unwrap();
17 //! ctx.encrypt_init(Some(cipher), Some(key), Some(iv)).unwrap();
18 //!
19 //! let mut ciphertext = vec![];
20 //! ctx.cipher_update_vec(data, &mut ciphertext).unwrap();
21 //! ctx.cipher_final_vec(&mut ciphertext).unwrap();
22 //!
23 //! assert_eq!(
24 //!     b"\xB4\xB9\xE7\x30\xD6\xD6\xF7\xDE\x77\x3F\x1C\xFF\xB3\x3E\x44\x5A\x91\xD7\x27\x62\x87\x4D\
25 //!       \xFB\x3C\x5E\xC4\x59\x72\x4A\xF4\x7C\xA1",
26 //!     &ciphertext[..],
27 //! );
28 //! ```
29 //!
30 //! Decrypt data with AES128 CBC
31 //!
32 //! ```
33 //! use openssl::cipher::Cipher;
34 //! use openssl::cipher_ctx::CipherCtx;
35 //!
36 //! let cipher = Cipher::aes_128_cbc();
37 //! let data = b"\xB4\xB9\xE7\x30\xD6\xD6\xF7\xDE\x77\x3F\x1C\xFF\xB3\x3E\x44\x5A\x91\xD7\x27\x62\
38 //!              \x87\x4D\xFB\x3C\x5E\xC4\x59\x72\x4A\xF4\x7C\xA1";
39 //! let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F";
40 //! let iv = b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07";
41 //!
42 //! let mut ctx = CipherCtx::new().unwrap();
43 //! ctx.decrypt_init(Some(cipher), Some(key), Some(iv)).unwrap();
44 //!
45 //! let mut plaintext = vec![];
46 //! ctx.cipher_update_vec(data, &mut plaintext).unwrap();
47 //! ctx.cipher_final_vec(&mut plaintext).unwrap();
48 //!
49 //! assert_eq!(b"Some Crypto Text", &plaintext[..]);
50 //! ```
51 #![warn(missing_docs)]
52 
53 use crate::cipher::CipherRef;
54 use crate::error::ErrorStack;
55 #[cfg(not(boringssl))]
56 use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef};
57 use crate::{cvt, cvt_p};
58 use cfg_if::cfg_if;
59 use foreign_types::{ForeignType, ForeignTypeRef};
60 use libc::{c_int, c_uchar};
61 use openssl_macros::corresponds;
62 use std::convert::{TryFrom, TryInto};
63 use std::ptr;
64 
65 cfg_if! {
66     if #[cfg(ossl300)] {
67         use ffi::EVP_CIPHER_CTX_get0_cipher;
68     } else {
69         use ffi::EVP_CIPHER_CTX_cipher as EVP_CIPHER_CTX_get0_cipher;
70     }
71 }
72 
73 foreign_type_and_impl_send_sync! {
74     type CType = ffi::EVP_CIPHER_CTX;
75     fn drop = ffi::EVP_CIPHER_CTX_free;
76 
77     /// A context object used to perform symmetric encryption operations.
78     pub struct CipherCtx;
79     /// A reference to a [`CipherCtx`].
80     pub struct CipherCtxRef;
81 }
82 
83 impl CipherCtx {
84     /// Creates a new context.
85     #[corresponds(EVP_CIPHER_CTX_new)]
new() -> Result<Self, ErrorStack>86     pub fn new() -> Result<Self, ErrorStack> {
87         ffi::init();
88 
89         unsafe {
90             let ptr = cvt_p(ffi::EVP_CIPHER_CTX_new())?;
91             Ok(CipherCtx::from_ptr(ptr))
92         }
93     }
94 }
95 
96 impl CipherCtxRef {
97     /// Initializes the context for encryption.
98     ///
99     /// Normally this is called once to set all of the cipher, key, and IV. However, this process can be split up
100     /// by first setting the cipher with no key or IV and then setting the key and IV with no cipher. This can be used
101     /// to, for example, use a nonstandard IV size.
102     ///
103     /// # Panics
104     ///
105     /// Panics if the key buffer is smaller than the key size of the cipher, the IV buffer is smaller than the IV size
106     /// of the cipher, or if a key or IV is provided before a cipher.
107     #[corresponds(EVP_EncryptInit_ex)]
encrypt_init( &mut self, type_: Option<&CipherRef>, key: Option<&[u8]>, iv: Option<&[u8]>, ) -> Result<(), ErrorStack>108     pub fn encrypt_init(
109         &mut self,
110         type_: Option<&CipherRef>,
111         key: Option<&[u8]>,
112         iv: Option<&[u8]>,
113     ) -> Result<(), ErrorStack> {
114         self.cipher_init(type_, key, iv, ffi::EVP_EncryptInit_ex)
115     }
116 
117     /// Initializes the context for decryption.
118     ///
119     /// Normally this is called once to set all of the cipher, key, and IV. However, this process can be split up
120     /// by first setting the cipher with no key or IV and then setting the key and IV with no cipher. This can be used
121     /// to, for example, use a nonstandard IV size.
122     ///
123     /// # Panics
124     ///
125     /// Panics if the key buffer is smaller than the key size of the cipher, the IV buffer is smaller than the IV size
126     /// of the cipher, or if a key or IV is provided before a cipher.
127     #[corresponds(EVP_DecryptInit_ex)]
decrypt_init( &mut self, type_: Option<&CipherRef>, key: Option<&[u8]>, iv: Option<&[u8]>, ) -> Result<(), ErrorStack>128     pub fn decrypt_init(
129         &mut self,
130         type_: Option<&CipherRef>,
131         key: Option<&[u8]>,
132         iv: Option<&[u8]>,
133     ) -> Result<(), ErrorStack> {
134         self.cipher_init(type_, key, iv, ffi::EVP_DecryptInit_ex)
135     }
136 
cipher_init( &mut self, type_: Option<&CipherRef>, key: Option<&[u8]>, iv: Option<&[u8]>, f: unsafe extern "C" fn( *mut ffi::EVP_CIPHER_CTX, *const ffi::EVP_CIPHER, *mut ffi::ENGINE, *const c_uchar, *const c_uchar, ) -> c_int, ) -> Result<(), ErrorStack>137     fn cipher_init(
138         &mut self,
139         type_: Option<&CipherRef>,
140         key: Option<&[u8]>,
141         iv: Option<&[u8]>,
142         f: unsafe extern "C" fn(
143             *mut ffi::EVP_CIPHER_CTX,
144             *const ffi::EVP_CIPHER,
145             *mut ffi::ENGINE,
146             *const c_uchar,
147             *const c_uchar,
148         ) -> c_int,
149     ) -> Result<(), ErrorStack> {
150         if let Some(key) = key {
151             let key_len = type_.map_or_else(|| self.key_length(), |c| c.key_length());
152             assert!(key_len <= key.len());
153         }
154 
155         if let Some(iv) = iv {
156             let iv_len = type_.map_or_else(|| self.iv_length(), |c| c.iv_length());
157             assert!(iv_len <= iv.len());
158         }
159 
160         unsafe {
161             cvt(f(
162                 self.as_ptr(),
163                 type_.map_or(ptr::null(), |p| p.as_ptr()),
164                 ptr::null_mut(),
165                 key.map_or(ptr::null(), |k| k.as_ptr()),
166                 iv.map_or(ptr::null(), |iv| iv.as_ptr()),
167             ))?;
168         }
169 
170         Ok(())
171     }
172 
173     /// Initializes the context to perform envelope encryption.
174     ///
175     /// Normally this is called once to set both the cipher and public keys. However, this process may be split up by
176     /// first providing the cipher with no public keys and then setting the public keys with no cipher.
177     ///
178     /// `encrypted_keys` will contain the generated symmetric key encrypted with each corresponding asymmetric private
179     /// key. The generated IV will be written to `iv`.
180     ///
181     /// # Panics
182     ///
183     /// Panics if `pub_keys` is not the same size as `encrypted_keys`, the IV buffer is smaller than the cipher's IV
184     /// size, or if an IV is provided before the cipher.
185     #[corresponds(EVP_SealInit)]
186     #[cfg(not(boringssl))]
seal_init<T>( &mut self, type_: Option<&CipherRef>, pub_keys: &[PKey<T>], encrypted_keys: &mut [Vec<u8>], iv: Option<&mut [u8]>, ) -> Result<(), ErrorStack> where T: HasPublic,187     pub fn seal_init<T>(
188         &mut self,
189         type_: Option<&CipherRef>,
190         pub_keys: &[PKey<T>],
191         encrypted_keys: &mut [Vec<u8>],
192         iv: Option<&mut [u8]>,
193     ) -> Result<(), ErrorStack>
194     where
195         T: HasPublic,
196     {
197         assert_eq!(pub_keys.len(), encrypted_keys.len());
198         if !pub_keys.is_empty() {
199             let iv_len = type_.map_or_else(|| self.iv_length(), |c| c.iv_length());
200             assert!(iv.as_ref().map_or(0, |b| b.len()) >= iv_len);
201         }
202 
203         for (pub_key, buf) in pub_keys.iter().zip(&mut *encrypted_keys) {
204             buf.resize(pub_key.size(), 0);
205         }
206 
207         let mut keys = encrypted_keys
208             .iter_mut()
209             .map(|b| b.as_mut_ptr())
210             .collect::<Vec<_>>();
211         let mut key_lengths = vec![0; pub_keys.len()];
212         let pub_keys_len = i32::try_from(pub_keys.len()).unwrap();
213 
214         unsafe {
215             cvt(ffi::EVP_SealInit(
216                 self.as_ptr(),
217                 type_.map_or(ptr::null(), |p| p.as_ptr()),
218                 keys.as_mut_ptr(),
219                 key_lengths.as_mut_ptr(),
220                 iv.map_or(ptr::null_mut(), |b| b.as_mut_ptr()),
221                 pub_keys.as_ptr() as *mut _,
222                 pub_keys_len,
223             ))?;
224         }
225 
226         for (buf, len) in encrypted_keys.iter_mut().zip(key_lengths) {
227             buf.truncate(len as usize);
228         }
229 
230         Ok(())
231     }
232 
233     /// Initializes the context to perform envelope decryption.
234     ///
235     /// Normally this is called once with all of the arguments present. However, this process may be split up by first
236     /// providing the cipher alone and then after providing the rest of the arguments in a second call.
237     ///
238     /// # Panics
239     ///
240     /// Panics if the IV buffer is smaller than the cipher's required IV size or if the IV is provided before the
241     /// cipher.
242     #[corresponds(EVP_OpenInit)]
243     #[cfg(not(boringssl))]
open_init<T>( &mut self, type_: Option<&CipherRef>, encrypted_key: &[u8], iv: Option<&[u8]>, priv_key: Option<&PKeyRef<T>>, ) -> Result<(), ErrorStack> where T: HasPrivate,244     pub fn open_init<T>(
245         &mut self,
246         type_: Option<&CipherRef>,
247         encrypted_key: &[u8],
248         iv: Option<&[u8]>,
249         priv_key: Option<&PKeyRef<T>>,
250     ) -> Result<(), ErrorStack>
251     where
252         T: HasPrivate,
253     {
254         if priv_key.is_some() {
255             let iv_len = type_.map_or_else(|| self.iv_length(), |c| c.iv_length());
256             assert!(iv.map_or(0, |b| b.len()) >= iv_len);
257         }
258 
259         let len = c_int::try_from(encrypted_key.len()).unwrap();
260         unsafe {
261             cvt(ffi::EVP_OpenInit(
262                 self.as_ptr(),
263                 type_.map_or(ptr::null(), |p| p.as_ptr()),
264                 encrypted_key.as_ptr(),
265                 len,
266                 iv.map_or(ptr::null(), |b| b.as_ptr()),
267                 priv_key.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr),
268             ))?;
269         }
270 
271         Ok(())
272     }
273 
assert_cipher(&self)274     fn assert_cipher(&self) {
275         unsafe {
276             assert!(!EVP_CIPHER_CTX_get0_cipher(self.as_ptr()).is_null());
277         }
278     }
279 
280     /// Returns the block size of the context's cipher.
281     ///
282     /// Stream ciphers will report a block size of 1.
283     ///
284     /// # Panics
285     ///
286     /// Panics if the context has not been initialized with a cipher.
287     #[corresponds(EVP_CIPHER_CTX_block_size)]
block_size(&self) -> usize288     pub fn block_size(&self) -> usize {
289         self.assert_cipher();
290 
291         unsafe { ffi::EVP_CIPHER_CTX_block_size(self.as_ptr()) as usize }
292     }
293 
294     /// Returns the key length of the context's cipher.
295     ///
296     /// # Panics
297     ///
298     /// Panics if the context has not been initialized with a cipher.
299     #[corresponds(EVP_CIPHER_CTX_key_length)]
key_length(&self) -> usize300     pub fn key_length(&self) -> usize {
301         self.assert_cipher();
302 
303         unsafe { ffi::EVP_CIPHER_CTX_key_length(self.as_ptr()) as usize }
304     }
305 
306     /// Generates a random key based on the configured cipher.
307     ///
308     /// # Panics
309     ///
310     /// Panics if the context has not been initialized with a cipher or if the buffer is smaller than the cipher's key
311     /// length.
312     ///
313     /// This corresponds to [`EVP_CIPHER_CTX_rand_key`].
314     ///
315     /// [`EVP_CIPHER_CTX_rand_key`]: https://www.openssl.org/docs/manmaster/man3/EVP_CIPHER_CTX_rand_key.html
316     #[corresponds(EVP_CIPHER_CTX_rand_key)]
317     #[cfg(not(boringssl))]
rand_key(&self, buf: &mut [u8]) -> Result<(), ErrorStack>318     pub fn rand_key(&self, buf: &mut [u8]) -> Result<(), ErrorStack> {
319         assert!(buf.len() >= self.key_length());
320 
321         unsafe {
322             cvt(ffi::EVP_CIPHER_CTX_rand_key(
323                 self.as_ptr(),
324                 buf.as_mut_ptr(),
325             ))?;
326         }
327 
328         Ok(())
329     }
330 
331     /// Sets the length of the key expected by the context.
332     ///
333     /// Only some ciphers support configurable key lengths.
334     ///
335     /// # Panics
336     ///
337     /// Panics if the context has not been initialized with a cipher.
338     #[corresponds(EVP_CIPHER_CTX_set_key_length)]
set_key_length(&mut self, len: usize) -> Result<(), ErrorStack>339     pub fn set_key_length(&mut self, len: usize) -> Result<(), ErrorStack> {
340         self.assert_cipher();
341 
342         unsafe {
343             cvt(ffi::EVP_CIPHER_CTX_set_key_length(
344                 self.as_ptr(),
345                 len.try_into().unwrap(),
346             ))?;
347         }
348 
349         Ok(())
350     }
351 
352     /// Returns the length of the IV expected by this context.
353     ///
354     /// Returns 0 if the cipher does not use an IV.
355     ///
356     /// # Panics
357     ///
358     /// Panics if the context has not been initialized with a cipher.
359     #[corresponds(EVP_CIPHER_CTX_iv_length)]
iv_length(&self) -> usize360     pub fn iv_length(&self) -> usize {
361         self.assert_cipher();
362 
363         unsafe { ffi::EVP_CIPHER_CTX_iv_length(self.as_ptr()) as usize }
364     }
365 
366     /// Returns the `num` parameter of the cipher.
367     ///
368     /// Built-in ciphers typically use this to track how much of the
369     /// current underlying block has been "used" already.
370     ///
371     /// # Panics
372     ///
373     /// Panics if the context has not been initialized with a cipher.
374     #[corresponds(EVP_CIPHER_CTX_num)]
375     #[cfg(ossl110)]
num(&self) -> usize376     pub fn num(&self) -> usize {
377         self.assert_cipher();
378 
379         unsafe { ffi::EVP_CIPHER_CTX_num(self.as_ptr()) as usize }
380     }
381 
382     /// Sets the length of the IV expected by this context.
383     ///
384     /// Only some ciphers support configurable IV lengths.
385     ///
386     /// # Panics
387     ///
388     /// Panics if the context has not been initialized with a cipher.
389     #[corresponds(EVP_CIHPER_CTX_ctrl)]
set_iv_length(&mut self, len: usize) -> Result<(), ErrorStack>390     pub fn set_iv_length(&mut self, len: usize) -> Result<(), ErrorStack> {
391         self.assert_cipher();
392 
393         let len = c_int::try_from(len).unwrap();
394 
395         unsafe {
396             cvt(ffi::EVP_CIPHER_CTX_ctrl(
397                 self.as_ptr(),
398                 ffi::EVP_CTRL_GCM_SET_IVLEN,
399                 len,
400                 ptr::null_mut(),
401             ))?;
402         }
403 
404         Ok(())
405     }
406 
407     /// Returns the length of the authentication tag expected by this context.
408     ///
409     /// Returns 0 if the cipher is not authenticated.
410     ///
411     /// # Panics
412     ///
413     /// Panics if the context has not been initialized with a cipher.
414     ///
415     /// Requires OpenSSL 3.0.0 or newer.
416     #[corresponds(EVP_CIPHER_CTX_get_tag_length)]
417     #[cfg(ossl300)]
tag_length(&self) -> usize418     pub fn tag_length(&self) -> usize {
419         self.assert_cipher();
420 
421         unsafe { ffi::EVP_CIPHER_CTX_get_tag_length(self.as_ptr()) as usize }
422     }
423 
424     /// Retrieves the calculated authentication tag from the context.
425     ///
426     /// This should be called after [`Self::cipher_final`], and is only supported by authenticated ciphers.
427     ///
428     /// The size of the buffer indicates the size of the tag. While some ciphers support a range of tag sizes, it is
429     /// recommended to pick the maximum size.
430     #[corresponds(EVP_CIPHER_CTX_ctrl)]
tag(&self, tag: &mut [u8]) -> Result<(), ErrorStack>431     pub fn tag(&self, tag: &mut [u8]) -> Result<(), ErrorStack> {
432         let len = c_int::try_from(tag.len()).unwrap();
433 
434         unsafe {
435             cvt(ffi::EVP_CIPHER_CTX_ctrl(
436                 self.as_ptr(),
437                 ffi::EVP_CTRL_GCM_GET_TAG,
438                 len,
439                 tag.as_mut_ptr() as *mut _,
440             ))?;
441         }
442 
443         Ok(())
444     }
445 
446     /// Sets the length of the generated authentication tag.
447     ///
448     /// This must be called when encrypting with a cipher in CCM mode to use a tag size other than the default.
449     #[corresponds(EVP_CIPHER_CTX_ctrl)]
set_tag_length(&mut self, len: usize) -> Result<(), ErrorStack>450     pub fn set_tag_length(&mut self, len: usize) -> Result<(), ErrorStack> {
451         let len = c_int::try_from(len).unwrap();
452 
453         unsafe {
454             cvt(ffi::EVP_CIPHER_CTX_ctrl(
455                 self.as_ptr(),
456                 ffi::EVP_CTRL_GCM_SET_TAG,
457                 len,
458                 ptr::null_mut(),
459             ))?;
460         }
461 
462         Ok(())
463     }
464 
465     /// Sets the authentication tag for verification during decryption.
466     #[corresponds(EVP_CIPHER_CTX_ctrl)]
set_tag(&mut self, tag: &[u8]) -> Result<(), ErrorStack>467     pub fn set_tag(&mut self, tag: &[u8]) -> Result<(), ErrorStack> {
468         let len = c_int::try_from(tag.len()).unwrap();
469 
470         unsafe {
471             cvt(ffi::EVP_CIPHER_CTX_ctrl(
472                 self.as_ptr(),
473                 ffi::EVP_CTRL_GCM_SET_TAG,
474                 len,
475                 tag.as_ptr() as *mut _,
476             ))?;
477         }
478 
479         Ok(())
480     }
481 
482     /// Enables or disables padding.
483     ///
484     /// If padding is disabled, the plaintext must be an exact multiple of the cipher's block size.
485     #[corresponds(EVP_CIPHER_CTX_set_padding)]
set_padding(&mut self, padding: bool)486     pub fn set_padding(&mut self, padding: bool) {
487         unsafe {
488             ffi::EVP_CIPHER_CTX_set_padding(self.as_ptr(), padding as c_int);
489         }
490     }
491 
492     /// Sets the total length of plaintext data.
493     ///
494     /// This is required for ciphers operating in CCM mode.
495     #[corresponds(EVP_CipherUpdate)]
set_data_len(&mut self, len: usize) -> Result<(), ErrorStack>496     pub fn set_data_len(&mut self, len: usize) -> Result<(), ErrorStack> {
497         let len = c_int::try_from(len).unwrap();
498 
499         unsafe {
500             cvt(ffi::EVP_CipherUpdate(
501                 self.as_ptr(),
502                 ptr::null_mut(),
503                 &mut 0,
504                 ptr::null(),
505                 len,
506             ))?;
507         }
508 
509         Ok(())
510     }
511 
512     /// Writes data into the context.
513     ///
514     /// Providing no output buffer will cause the input to be considered additional authenticated data (AAD).
515     ///
516     /// Returns the number of bytes written to `output`.
517     ///
518     /// # Panics
519     ///
520     /// Panics if `output` doesn't contain enough space for data to be
521     /// written as specified by [`Self::minimal_output_size`].
522     #[corresponds(EVP_CipherUpdate)]
cipher_update( &mut self, input: &[u8], output: Option<&mut [u8]>, ) -> Result<usize, ErrorStack>523     pub fn cipher_update(
524         &mut self,
525         input: &[u8],
526         output: Option<&mut [u8]>,
527     ) -> Result<usize, ErrorStack> {
528         if let Some(output) = &output {
529             let mut block_size = self.block_size();
530             if block_size == 1 {
531                 block_size = 0;
532             }
533             let min_output_size = input.len() + block_size;
534             assert!(
535                 output.len() >= min_output_size,
536                 "Output buffer size should be at least {} bytes.",
537                 min_output_size
538             );
539         }
540 
541         unsafe { self.cipher_update_unchecked(input, output) }
542     }
543 
544     /// Writes data into the context.
545     ///
546     /// Providing no output buffer will cause the input to be considered additional authenticated data (AAD).
547     ///
548     /// Returns the number of bytes written to `output`.
549     ///
550     /// This function is the same as [`Self::cipher_update`] but with the
551     /// output size check removed. It can be used when the exact
552     /// buffer size control is maintained by the caller.
553     ///
554     /// SAFETY: The caller is expected to provide `output` buffer
555     /// large enough to contain correct number of bytes. For streaming
556     /// ciphers the output buffer size should be at least as big as
557     /// the input buffer. For block ciphers the size of the output
558     /// buffer depends on the state of partially updated blocks.
559     #[corresponds(EVP_CipherUpdate)]
cipher_update_unchecked( &mut self, input: &[u8], output: Option<&mut [u8]>, ) -> Result<usize, ErrorStack>560     pub unsafe fn cipher_update_unchecked(
561         &mut self,
562         input: &[u8],
563         output: Option<&mut [u8]>,
564     ) -> Result<usize, ErrorStack> {
565         let inlen = c_int::try_from(input.len()).unwrap();
566 
567         let mut outlen = 0;
568 
569         cvt(ffi::EVP_CipherUpdate(
570             self.as_ptr(),
571             output.map_or(ptr::null_mut(), |b| b.as_mut_ptr()),
572             &mut outlen,
573             input.as_ptr(),
574             inlen,
575         ))?;
576 
577         Ok(outlen as usize)
578     }
579 
580     /// Like [`Self::cipher_update`] except that it appends output to a [`Vec`].
cipher_update_vec( &mut self, input: &[u8], output: &mut Vec<u8>, ) -> Result<usize, ErrorStack>581     pub fn cipher_update_vec(
582         &mut self,
583         input: &[u8],
584         output: &mut Vec<u8>,
585     ) -> Result<usize, ErrorStack> {
586         let base = output.len();
587         output.resize(base + input.len() + self.block_size(), 0);
588         let len = self.cipher_update(input, Some(&mut output[base..]))?;
589         output.truncate(base + len);
590 
591         Ok(len)
592     }
593 
594     /// Finalizes the encryption or decryption process.
595     ///
596     /// Any remaining data will be written to the output buffer.
597     ///
598     /// Returns the number of bytes written to `output`.
599     ///
600     /// # Panics
601     ///
602     /// Panics if `output` is smaller than the cipher's block size.
603     #[corresponds(EVP_CipherFinal)]
cipher_final(&mut self, output: &mut [u8]) -> Result<usize, ErrorStack>604     pub fn cipher_final(&mut self, output: &mut [u8]) -> Result<usize, ErrorStack> {
605         let block_size = self.block_size();
606         if block_size > 1 {
607             assert!(output.len() >= block_size);
608         }
609 
610         unsafe { self.cipher_final_unchecked(output) }
611     }
612 
613     /// Finalizes the encryption or decryption process.
614     ///
615     /// Any remaining data will be written to the output buffer.
616     ///
617     /// Returns the number of bytes written to `output`.
618     ///
619     /// This function is the same as [`Self::cipher_final`] but with
620     /// the output buffer size check removed.
621     ///
622     /// SAFETY: The caller is expected to provide `output` buffer
623     /// large enough to contain correct number of bytes. For streaming
624     /// ciphers the output buffer can be empty, for block ciphers the
625     /// output buffer should be at least as big as the block.
626     #[corresponds(EVP_CipherFinal)]
cipher_final_unchecked( &mut self, output: &mut [u8], ) -> Result<usize, ErrorStack>627     pub unsafe fn cipher_final_unchecked(
628         &mut self,
629         output: &mut [u8],
630     ) -> Result<usize, ErrorStack> {
631         let mut outl = 0;
632 
633         cvt(ffi::EVP_CipherFinal(
634             self.as_ptr(),
635             output.as_mut_ptr(),
636             &mut outl,
637         ))?;
638 
639         Ok(outl as usize)
640     }
641 
642     /// Like [`Self::cipher_final`] except that it appends output to a [`Vec`].
cipher_final_vec(&mut self, output: &mut Vec<u8>) -> Result<usize, ErrorStack>643     pub fn cipher_final_vec(&mut self, output: &mut Vec<u8>) -> Result<usize, ErrorStack> {
644         let base = output.len();
645         output.resize(base + self.block_size(), 0);
646         let len = self.cipher_final(&mut output[base..])?;
647         output.truncate(base + len);
648 
649         Ok(len)
650     }
651 }
652 
653 #[cfg(test)]
654 mod test {
655     use super::*;
656     use crate::{cipher::Cipher, rand::rand_bytes};
657     #[cfg(not(boringssl))]
658     use std::slice;
659 
660     #[test]
661     #[cfg(not(boringssl))]
seal_open()662     fn seal_open() {
663         let private_pem = include_bytes!("../test/rsa.pem");
664         let public_pem = include_bytes!("../test/rsa.pem.pub");
665         let private_key = PKey::private_key_from_pem(private_pem).unwrap();
666         let public_key = PKey::public_key_from_pem(public_pem).unwrap();
667         let cipher = Cipher::aes_256_cbc();
668         let secret = b"My secret message";
669 
670         let mut ctx = CipherCtx::new().unwrap();
671         let mut encrypted_key = vec![];
672         let mut iv = vec![0; cipher.iv_length()];
673         let mut encrypted = vec![];
674         ctx.seal_init(
675             Some(cipher),
676             &[public_key],
677             slice::from_mut(&mut encrypted_key),
678             Some(&mut iv),
679         )
680         .unwrap();
681         ctx.cipher_update_vec(secret, &mut encrypted).unwrap();
682         ctx.cipher_final_vec(&mut encrypted).unwrap();
683 
684         let mut decrypted = vec![];
685         ctx.open_init(Some(cipher), &encrypted_key, Some(&iv), Some(&private_key))
686             .unwrap();
687         ctx.cipher_update_vec(&encrypted, &mut decrypted).unwrap();
688         ctx.cipher_final_vec(&mut decrypted).unwrap();
689 
690         assert_eq!(secret, &decrypted[..]);
691     }
692 
aes_128_cbc(cipher: &CipherRef)693     fn aes_128_cbc(cipher: &CipherRef) {
694         // from https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf
695         let key = hex::decode("2b7e151628aed2a6abf7158809cf4f3c").unwrap();
696         let iv = hex::decode("000102030405060708090a0b0c0d0e0f").unwrap();
697         let pt = hex::decode("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51")
698             .unwrap();
699         let ct = hex::decode("7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b2")
700             .unwrap();
701 
702         let mut ctx = CipherCtx::new().unwrap();
703 
704         ctx.encrypt_init(Some(cipher), Some(&key), Some(&iv))
705             .unwrap();
706         ctx.set_padding(false);
707 
708         let mut buf = vec![];
709         ctx.cipher_update_vec(&pt, &mut buf).unwrap();
710         ctx.cipher_final_vec(&mut buf).unwrap();
711 
712         assert_eq!(buf, ct);
713 
714         ctx.decrypt_init(Some(cipher), Some(&key), Some(&iv))
715             .unwrap();
716         ctx.set_padding(false);
717 
718         let mut buf = vec![];
719         ctx.cipher_update_vec(&ct, &mut buf).unwrap();
720         ctx.cipher_final_vec(&mut buf).unwrap();
721 
722         assert_eq!(buf, pt);
723     }
724 
725     #[test]
726     #[cfg(ossl300)]
fetched_aes_128_cbc()727     fn fetched_aes_128_cbc() {
728         let cipher = Cipher::fetch(None, "AES-128-CBC", None).unwrap();
729         aes_128_cbc(&cipher);
730     }
731 
732     #[test]
default_aes_128_cbc()733     fn default_aes_128_cbc() {
734         let cipher = Cipher::aes_128_cbc();
735         aes_128_cbc(cipher);
736     }
737 
738     #[test]
test_stream_ciphers()739     fn test_stream_ciphers() {
740         test_stream_cipher(Cipher::aes_192_ctr());
741         test_stream_cipher(Cipher::aes_256_ctr());
742     }
743 
test_stream_cipher(cipher: &'static CipherRef)744     fn test_stream_cipher(cipher: &'static CipherRef) {
745         let mut key = vec![0; cipher.key_length()];
746         rand_bytes(&mut key).unwrap();
747         let mut iv = vec![0; cipher.iv_length()];
748         rand_bytes(&mut iv).unwrap();
749 
750         let mut ctx = CipherCtx::new().unwrap();
751 
752         ctx.encrypt_init(Some(cipher), Some(&key), Some(&iv))
753             .unwrap();
754         ctx.set_padding(false);
755 
756         assert_eq!(
757             1,
758             cipher.block_size(),
759             "Need a stream cipher, not a block cipher"
760         );
761 
762         // update cipher with non-full block
763         // this is a streaming cipher so the number of output bytes
764         // will be the same as the number of input bytes
765         let mut output = vec![0; 32];
766         let outlen = ctx
767             .cipher_update(&[1; 15], Some(&mut output[0..15]))
768             .unwrap();
769         assert_eq!(15, outlen);
770 
771         // update cipher with missing bytes from the previous block
772         // as previously it will output the same number of bytes as
773         // the input
774         let outlen = ctx
775             .cipher_update(&[1; 17], Some(&mut output[15..]))
776             .unwrap();
777         assert_eq!(17, outlen);
778 
779         ctx.cipher_final_vec(&mut vec![0; 0]).unwrap();
780 
781         // try to decrypt
782         ctx.decrypt_init(Some(cipher), Some(&key), Some(&iv))
783             .unwrap();
784         ctx.set_padding(false);
785 
786         // update cipher with non-full block
787         // expect that the output for stream cipher will contain
788         // the same number of bytes as the input
789         let mut output_decrypted = vec![0; 32];
790         let outlen = ctx
791             .cipher_update(&output[0..15], Some(&mut output_decrypted[0..15]))
792             .unwrap();
793         assert_eq!(15, outlen);
794 
795         let outlen = ctx
796             .cipher_update(&output[15..], Some(&mut output_decrypted[15..]))
797             .unwrap();
798         assert_eq!(17, outlen);
799 
800         ctx.cipher_final_vec(&mut vec![0; 0]).unwrap();
801         // check if the decrypted blocks are the same as input (all ones)
802         assert_eq!(output_decrypted, vec![1; 32]);
803     }
804 
805     #[test]
806     #[should_panic(expected = "Output buffer size should be at least 33 bytes.")]
full_block_updates_aes_128()807     fn full_block_updates_aes_128() {
808         output_buffer_too_small(Cipher::aes_128_cbc());
809     }
810 
811     #[test]
812     #[should_panic(expected = "Output buffer size should be at least 33 bytes.")]
full_block_updates_aes_256()813     fn full_block_updates_aes_256() {
814         output_buffer_too_small(Cipher::aes_256_cbc());
815     }
816 
817     #[test]
818     #[should_panic(expected = "Output buffer size should be at least 17 bytes.")]
full_block_updates_3des()819     fn full_block_updates_3des() {
820         output_buffer_too_small(Cipher::des_ede3_cbc());
821     }
822 
output_buffer_too_small(cipher: &'static CipherRef)823     fn output_buffer_too_small(cipher: &'static CipherRef) {
824         let mut key = vec![0; cipher.key_length()];
825         rand_bytes(&mut key).unwrap();
826         let mut iv = vec![0; cipher.iv_length()];
827         rand_bytes(&mut iv).unwrap();
828 
829         let mut ctx = CipherCtx::new().unwrap();
830 
831         ctx.encrypt_init(Some(cipher), Some(&key), Some(&iv))
832             .unwrap();
833         ctx.set_padding(false);
834 
835         let block_size = cipher.block_size();
836         assert!(block_size > 1, "Need a block cipher, not a stream cipher");
837 
838         ctx.cipher_update(&vec![0; block_size + 1], Some(&mut vec![0; block_size - 1]))
839             .unwrap();
840     }
841 }
842