Skip to main content

variant_ssl/
cipher_ctx.rs

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
53use crate::cipher::CipherRef;
54use crate::error::ErrorStack;
55#[cfg(not(any(boringssl, awslc)))]
56use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef};
57use crate::{cvt, cvt_p};
58#[cfg(ossl110)]
59use bitflags::bitflags;
60use cfg_if::cfg_if;
61use foreign_types::{ForeignType, ForeignTypeRef};
62use libc::{c_int, c_uchar};
63use openssl_macros::corresponds;
64use std::convert::{TryFrom, TryInto};
65use std::ptr;
66
67cfg_if! {
68    if #[cfg(ossl300)] {
69        use ffi::EVP_CIPHER_CTX_get0_cipher;
70    } else {
71        use ffi::EVP_CIPHER_CTX_cipher as EVP_CIPHER_CTX_get0_cipher;
72    }
73}
74
75foreign_type_and_impl_send_sync! {
76    type CType = ffi::EVP_CIPHER_CTX;
77    fn drop = ffi::EVP_CIPHER_CTX_free;
78
79    /// A context object used to perform symmetric encryption operations.
80    pub struct CipherCtx;
81    /// A reference to a [`CipherCtx`].
82    pub struct CipherCtxRef;
83}
84
85#[cfg(ossl110)]
86bitflags! {
87    /// Flags for `EVP_CIPHER_CTX`.
88    pub struct CipherCtxFlags : c_int {
89        /// The flag used to opt into AES key wrap ciphers.
90        const FLAG_WRAP_ALLOW = ffi::EVP_CIPHER_CTX_FLAG_WRAP_ALLOW;
91    }
92}
93
94impl CipherCtx {
95    /// Creates a new context.
96    #[corresponds(EVP_CIPHER_CTX_new)]
97    pub fn new() -> Result<Self, ErrorStack> {
98        ffi::init();
99
100        unsafe {
101            let ptr = cvt_p(ffi::EVP_CIPHER_CTX_new())?;
102            Ok(CipherCtx::from_ptr(ptr))
103        }
104    }
105}
106
107impl CipherCtxRef {
108    /// Clears all information from a cipher context
109    ///
110    /// This will free up any allocated memory associated with it, except the ctx itself
111    #[corresponds(EVP_CIPHER_CTX_reset)]
112    #[cfg(any(ossl110, libressl350))]
113    #[inline]
114    pub fn reset(&mut self) -> Result<(), ErrorStack> {
115        unsafe {
116            let _ = cvt(ffi::EVP_CIPHER_CTX_reset(self.as_ptr()))?;
117            Ok(())
118        }
119    }
120
121    /// Clears all information from a cipher context
122    ///
123    /// This will free up any allocated memory associated with it, except the ctx itself
124    #[corresponds(EVP_CIPHER_CTX_reset)]
125    #[cfg(any(boringssl, awslc))]
126    #[inline]
127    pub fn reset(&mut self) -> Result<(), ErrorStack> {
128        unsafe {
129            ffi::EVP_CIPHER_CTX_reset(self.as_ptr());
130            Ok(())
131        }
132    }
133
134    #[corresponds(EVP_CIPHER_CTX_copy)]
135    pub fn copy(&mut self, src: &CipherCtxRef) -> Result<(), ErrorStack> {
136        unsafe {
137            cvt(ffi::EVP_CIPHER_CTX_copy(self.as_ptr(), src.as_ptr()))?;
138            Ok(())
139        }
140    }
141
142    /// Initializes the context for encryption.
143    ///
144    /// Normally this is called once to set all of the cipher, key, and IV. However, this process can be split up
145    /// by first setting the cipher with no key or IV and then setting the key and IV with no cipher. This can be used
146    /// to, for example, use a nonstandard IV size.
147    ///
148    /// # Panics
149    ///
150    /// Panics if the key buffer is smaller than the key size of the cipher, the IV buffer is smaller than the IV size
151    /// of the cipher, or if a key or IV is provided before a cipher.
152    #[corresponds(EVP_EncryptInit_ex)]
153    pub fn encrypt_init(
154        &mut self,
155        type_: Option<&CipherRef>,
156        key: Option<&[u8]>,
157        iv: Option<&[u8]>,
158    ) -> Result<(), ErrorStack> {
159        self.cipher_init(type_, key, iv, ffi::EVP_EncryptInit_ex)
160    }
161
162    /// Initializes the context for decryption.
163    ///
164    /// Normally this is called once to set all of the cipher, key, and IV. However, this process can be split up
165    /// by first setting the cipher with no key or IV and then setting the key and IV with no cipher. This can be used
166    /// to, for example, use a nonstandard IV size.
167    ///
168    /// # Panics
169    ///
170    /// Panics if the key buffer is smaller than the key size of the cipher, the IV buffer is smaller than the IV size
171    /// of the cipher, or if a key or IV is provided before a cipher.
172    #[corresponds(EVP_DecryptInit_ex)]
173    pub fn decrypt_init(
174        &mut self,
175        type_: Option<&CipherRef>,
176        key: Option<&[u8]>,
177        iv: Option<&[u8]>,
178    ) -> Result<(), ErrorStack> {
179        self.cipher_init(type_, key, iv, ffi::EVP_DecryptInit_ex)
180    }
181
182    fn cipher_init(
183        &mut self,
184        type_: Option<&CipherRef>,
185        key: Option<&[u8]>,
186        iv: Option<&[u8]>,
187        f: unsafe extern "C" fn(
188            *mut ffi::EVP_CIPHER_CTX,
189            *const ffi::EVP_CIPHER,
190            *mut ffi::ENGINE,
191            *const c_uchar,
192            *const c_uchar,
193        ) -> c_int,
194    ) -> Result<(), ErrorStack> {
195        if let Some(key) = key {
196            let key_len = type_.map_or_else(|| self.key_length(), |c| c.key_length());
197            assert!(key_len <= key.len());
198        }
199
200        if let Some(iv) = iv {
201            let iv_len = type_.map_or_else(|| self.iv_length(), |c| c.iv_length());
202            assert!(iv_len <= iv.len());
203        }
204
205        unsafe {
206            cvt(f(
207                self.as_ptr(),
208                type_.map_or(ptr::null(), |p| p.as_ptr()),
209                ptr::null_mut(),
210                key.map_or(ptr::null(), |k| k.as_ptr()),
211                iv.map_or(ptr::null(), |iv| iv.as_ptr()),
212            ))?;
213        }
214
215        Ok(())
216    }
217
218    /// Initializes the context to perform envelope encryption.
219    ///
220    /// Normally this is called once to set both the cipher and public keys. However, this process may be split up by
221    /// first providing the cipher with no public keys and then setting the public keys with no cipher.
222    ///
223    /// `encrypted_keys` will contain the generated symmetric key encrypted with each corresponding asymmetric private
224    /// key. The generated IV will be written to `iv`.
225    ///
226    /// # Panics
227    ///
228    /// Panics if `pub_keys` is not the same size as `encrypted_keys`, the IV buffer is smaller than the cipher's IV
229    /// size, or if an IV is provided before the cipher.
230    #[corresponds(EVP_SealInit)]
231    #[cfg(not(any(boringssl, awslc)))]
232    pub fn seal_init<T>(
233        &mut self,
234        type_: Option<&CipherRef>,
235        pub_keys: &[PKey<T>],
236        encrypted_keys: &mut [Vec<u8>],
237        iv: Option<&mut [u8]>,
238    ) -> Result<(), ErrorStack>
239    where
240        T: HasPublic,
241    {
242        assert_eq!(pub_keys.len(), encrypted_keys.len());
243        if !pub_keys.is_empty() {
244            let iv_len = type_.map_or_else(|| self.iv_length(), |c| c.iv_length());
245            assert!(iv.as_ref().map_or(0, |b| b.len()) >= iv_len);
246        }
247
248        for (pub_key, buf) in pub_keys.iter().zip(&mut *encrypted_keys) {
249            buf.resize(pub_key.size(), 0);
250        }
251
252        let mut keys = encrypted_keys
253            .iter_mut()
254            .map(|b| b.as_mut_ptr())
255            .collect::<Vec<_>>();
256        let mut key_lengths = vec![0; pub_keys.len()];
257        let pub_keys_len = i32::try_from(pub_keys.len()).unwrap();
258
259        unsafe {
260            cvt(ffi::EVP_SealInit(
261                self.as_ptr(),
262                type_.map_or(ptr::null(), |p| p.as_ptr()),
263                keys.as_mut_ptr(),
264                key_lengths.as_mut_ptr(),
265                iv.map_or(ptr::null_mut(), |b| b.as_mut_ptr()),
266                pub_keys.as_ptr() as *mut _,
267                pub_keys_len,
268            ))?;
269        }
270
271        for (buf, len) in encrypted_keys.iter_mut().zip(key_lengths) {
272            buf.truncate(len as usize);
273        }
274
275        Ok(())
276    }
277
278    /// Initializes the context to perform envelope decryption.
279    ///
280    /// Normally this is called once with all of the arguments present. However, this process may be split up by first
281    /// providing the cipher alone and then after providing the rest of the arguments in a second call.
282    ///
283    /// # Panics
284    ///
285    /// Panics if the IV buffer is smaller than the cipher's required IV size or if the IV is provided before the
286    /// cipher.
287    #[corresponds(EVP_OpenInit)]
288    #[cfg(not(any(boringssl, awslc)))]
289    pub fn open_init<T>(
290        &mut self,
291        type_: Option<&CipherRef>,
292        encrypted_key: &[u8],
293        iv: Option<&[u8]>,
294        priv_key: Option<&PKeyRef<T>>,
295    ) -> Result<(), ErrorStack>
296    where
297        T: HasPrivate,
298    {
299        if priv_key.is_some() {
300            let iv_len = type_.map_or_else(|| self.iv_length(), |c| c.iv_length());
301            assert!(iv.map_or(0, |b| b.len()) >= iv_len);
302        }
303
304        let len = c_int::try_from(encrypted_key.len()).unwrap();
305        unsafe {
306            cvt(ffi::EVP_OpenInit(
307                self.as_ptr(),
308                type_.map_or(ptr::null(), |p| p.as_ptr()),
309                encrypted_key.as_ptr(),
310                len,
311                iv.map_or(ptr::null(), |b| b.as_ptr()),
312                priv_key.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr),
313            ))?;
314        }
315
316        Ok(())
317    }
318
319    fn assert_cipher(&self) {
320        unsafe {
321            assert!(!EVP_CIPHER_CTX_get0_cipher(self.as_ptr()).is_null());
322        }
323    }
324
325    #[cfg(not(any(boringssl, awslc)))]
326    fn is_wrap_mode(&self) -> bool {
327        unsafe {
328            let cipher = EVP_CIPHER_CTX_get0_cipher(self.as_ptr());
329            if cipher.is_null() {
330                return false;
331            }
332            ffi::EVP_CIPHER_flags(cipher) & ffi::EVP_CIPH_MODE == ffi::EVP_CIPH_WRAP_MODE
333        }
334    }
335
336    #[cfg(any(boringssl, awslc))]
337    fn is_wrap_mode(&self) -> bool {
338        false
339    }
340
341    fn cipher_update_output_size(&self, input_len: usize) -> usize {
342        // Wrap-mode ciphers have EVP_CIPH_FLAG_CUSTOM_CIPHER set and emit their
343        // entire output (plaintext rounded up to 8 bytes + 8-byte IV) in a
344        // single update call, so the usual `inlen + block_size` bound is too
345        // small for key-wrap-with-padding inputs that aren't already a
346        // multiple of 8.
347        if self.is_wrap_mode() {
348            return input_len.saturating_add(7) / 8 * 8 + 8;
349        }
350        let mut block_size = self.block_size();
351        if block_size == 1 {
352            block_size = 0;
353        }
354        input_len + block_size
355    }
356
357    /// Returns the block size of the context's cipher.
358    ///
359    /// Stream ciphers will report a block size of 1.
360    ///
361    /// # Panics
362    ///
363    /// Panics if the context has not been initialized with a cipher.
364    #[corresponds(EVP_CIPHER_CTX_block_size)]
365    pub fn block_size(&self) -> usize {
366        self.assert_cipher();
367
368        unsafe { ffi::EVP_CIPHER_CTX_block_size(self.as_ptr()) as usize }
369    }
370
371    /// Returns the key length of the context's cipher.
372    ///
373    /// # Panics
374    ///
375    /// Panics if the context has not been initialized with a cipher.
376    #[corresponds(EVP_CIPHER_CTX_key_length)]
377    pub fn key_length(&self) -> usize {
378        self.assert_cipher();
379
380        unsafe { ffi::EVP_CIPHER_CTX_key_length(self.as_ptr()) as usize }
381    }
382
383    /// Generates a random key based on the configured cipher.
384    ///
385    /// # Panics
386    ///
387    /// Panics if the context has not been initialized with a cipher or if the buffer is smaller than the cipher's key
388    /// length.
389    #[corresponds(EVP_CIPHER_CTX_rand_key)]
390    #[cfg(not(any(boringssl, awslc)))]
391    pub fn rand_key(&self, buf: &mut [u8]) -> Result<(), ErrorStack> {
392        assert!(buf.len() >= self.key_length());
393
394        unsafe {
395            cvt(ffi::EVP_CIPHER_CTX_rand_key(
396                self.as_ptr(),
397                buf.as_mut_ptr(),
398            ))?;
399        }
400
401        Ok(())
402    }
403
404    /// Sets the length of the key expected by the context.
405    ///
406    /// Only some ciphers support configurable key lengths.
407    ///
408    /// # Panics
409    ///
410    /// Panics if the context has not been initialized with a cipher.
411    #[corresponds(EVP_CIPHER_CTX_set_key_length)]
412    pub fn set_key_length(&mut self, len: usize) -> Result<(), ErrorStack> {
413        self.assert_cipher();
414
415        unsafe {
416            cvt(ffi::EVP_CIPHER_CTX_set_key_length(
417                self.as_ptr(),
418                len.try_into().unwrap(),
419            ))?;
420        }
421
422        Ok(())
423    }
424
425    /// Returns the length of the IV expected by this context.
426    ///
427    /// Returns 0 if the cipher does not use an IV.
428    ///
429    /// # Panics
430    ///
431    /// Panics if the context has not been initialized with a cipher.
432    #[corresponds(EVP_CIPHER_CTX_iv_length)]
433    pub fn iv_length(&self) -> usize {
434        self.assert_cipher();
435
436        unsafe { ffi::EVP_CIPHER_CTX_iv_length(self.as_ptr()) as usize }
437    }
438
439    /// Returns the `num` parameter of the cipher.
440    ///
441    /// Built-in ciphers typically use this to track how much of the
442    /// current underlying block has been "used" already.
443    ///
444    /// # Panics
445    ///
446    /// Panics if the context has not been initialized with a cipher.
447    #[corresponds(EVP_CIPHER_CTX_num)]
448    #[cfg(ossl110)]
449    pub fn num(&self) -> usize {
450        self.assert_cipher();
451
452        unsafe { ffi::EVP_CIPHER_CTX_num(self.as_ptr()) as usize }
453    }
454
455    /// Sets the length of the IV expected by this context.
456    ///
457    /// Only some ciphers support configurable IV lengths.
458    ///
459    /// # Panics
460    ///
461    /// Panics if the context has not been initialized with a cipher.
462    #[corresponds(EVP_CIPHER_CTX_ctrl)]
463    pub fn set_iv_length(&mut self, len: usize) -> Result<(), ErrorStack> {
464        self.assert_cipher();
465
466        let len = c_int::try_from(len).unwrap();
467
468        unsafe {
469            cvt(ffi::EVP_CIPHER_CTX_ctrl(
470                self.as_ptr(),
471                ffi::EVP_CTRL_GCM_SET_IVLEN,
472                len,
473                ptr::null_mut(),
474            ))?;
475        }
476
477        Ok(())
478    }
479
480    /// Returns the length of the authentication tag expected by this context.
481    ///
482    /// Returns 0 if the cipher is not authenticated.
483    ///
484    /// # Panics
485    ///
486    /// Panics if the context has not been initialized with a cipher.
487    ///
488    /// Requires OpenSSL 3.0.0 or newer.
489    #[corresponds(EVP_CIPHER_CTX_get_tag_length)]
490    #[cfg(ossl300)]
491    pub fn tag_length(&self) -> usize {
492        self.assert_cipher();
493
494        unsafe { ffi::EVP_CIPHER_CTX_get_tag_length(self.as_ptr()) as usize }
495    }
496
497    /// Retrieves the calculated authentication tag from the context.
498    ///
499    /// This should be called after [`Self::cipher_final`], and is only supported by authenticated ciphers.
500    ///
501    /// The size of the buffer indicates the size of the tag. While some ciphers support a range of tag sizes, it is
502    /// recommended to pick the maximum size.
503    #[corresponds(EVP_CIPHER_CTX_ctrl)]
504    pub fn tag(&self, tag: &mut [u8]) -> Result<(), ErrorStack> {
505        let len = c_int::try_from(tag.len()).unwrap();
506
507        unsafe {
508            cvt(ffi::EVP_CIPHER_CTX_ctrl(
509                self.as_ptr(),
510                ffi::EVP_CTRL_GCM_GET_TAG,
511                len,
512                tag.as_mut_ptr() as *mut _,
513            ))?;
514        }
515
516        Ok(())
517    }
518
519    /// Sets the length of the generated authentication tag.
520    ///
521    /// This must be called when encrypting with a cipher in CCM mode to use a tag size other than the default.
522    #[corresponds(EVP_CIPHER_CTX_ctrl)]
523    pub fn set_tag_length(&mut self, len: usize) -> Result<(), ErrorStack> {
524        let len = c_int::try_from(len).unwrap();
525
526        unsafe {
527            cvt(ffi::EVP_CIPHER_CTX_ctrl(
528                self.as_ptr(),
529                ffi::EVP_CTRL_GCM_SET_TAG,
530                len,
531                ptr::null_mut(),
532            ))?;
533        }
534
535        Ok(())
536    }
537
538    /// Sets the authentication tag for verification during decryption.
539    #[corresponds(EVP_CIPHER_CTX_ctrl)]
540    pub fn set_tag(&mut self, tag: &[u8]) -> Result<(), ErrorStack> {
541        let len = c_int::try_from(tag.len()).unwrap();
542
543        unsafe {
544            cvt(ffi::EVP_CIPHER_CTX_ctrl(
545                self.as_ptr(),
546                ffi::EVP_CTRL_GCM_SET_TAG,
547                len,
548                tag.as_ptr() as *mut _,
549            ))?;
550        }
551
552        Ok(())
553    }
554
555    /// Enables or disables padding.
556    ///
557    /// If padding is disabled, the plaintext must be an exact multiple of the cipher's block size.
558    #[corresponds(EVP_CIPHER_CTX_set_padding)]
559    pub fn set_padding(&mut self, padding: bool) {
560        unsafe {
561            ffi::EVP_CIPHER_CTX_set_padding(self.as_ptr(), padding as c_int);
562        }
563    }
564
565    /// Sets the total length of plaintext data.
566    ///
567    /// This is required for ciphers operating in CCM mode.
568    #[corresponds(EVP_CipherUpdate)]
569    pub fn set_data_len(&mut self, len: usize) -> Result<(), ErrorStack> {
570        let len = c_int::try_from(len).unwrap();
571
572        unsafe {
573            cvt(ffi::EVP_CipherUpdate(
574                self.as_ptr(),
575                ptr::null_mut(),
576                &mut 0,
577                ptr::null(),
578                len,
579            ))?;
580        }
581
582        Ok(())
583    }
584
585    /// Set ctx flags.
586    ///
587    /// This function is currently used to enable AES key wrap feature supported by OpenSSL 1.1.0 or newer.
588    #[corresponds(EVP_CIPHER_CTX_set_flags)]
589    #[cfg(ossl110)]
590    pub fn set_flags(&mut self, flags: CipherCtxFlags) {
591        unsafe {
592            ffi::EVP_CIPHER_CTX_set_flags(self.as_ptr(), flags.bits());
593        }
594    }
595
596    /// Writes data into the context.
597    ///
598    /// Providing no output buffer will cause the input to be considered additional authenticated data (AAD).
599    ///
600    /// Returns the number of bytes written to `output`.
601    ///
602    /// # Panics
603    ///
604    /// Panics if `output` doesn't contain enough space for data to be
605    /// written.
606    #[corresponds(EVP_CipherUpdate)]
607    pub fn cipher_update(
608        &mut self,
609        input: &[u8],
610        output: Option<&mut [u8]>,
611    ) -> Result<usize, ErrorStack> {
612        if let Some(output) = &output {
613            let min_output_size = self.cipher_update_output_size(input.len());
614            assert!(
615                output.len() >= min_output_size,
616                "Output buffer size should be at least {} bytes.",
617                min_output_size
618            );
619        }
620
621        unsafe { self.cipher_update_unchecked(input, output) }
622    }
623
624    /// Writes data into the context.
625    ///
626    /// Providing no output buffer will cause the input to be considered additional authenticated data (AAD).
627    ///
628    /// Returns the number of bytes written to `output`.
629    ///
630    /// This function is the same as [`Self::cipher_update`] but with the
631    /// output size check removed. It can be used when the exact
632    /// buffer size control is maintained by the caller.
633    ///
634    /// # Safety
635    ///
636    /// The caller is expected to provide `output` buffer
637    /// large enough to contain correct number of bytes. For streaming
638    /// ciphers the output buffer size should be at least as big as
639    /// the input buffer. For block ciphers the size of the output
640    /// buffer depends on the state of partially updated blocks.
641    #[corresponds(EVP_CipherUpdate)]
642    pub unsafe fn cipher_update_unchecked(
643        &mut self,
644        input: &[u8],
645        output: Option<&mut [u8]>,
646    ) -> Result<usize, ErrorStack> {
647        let inlen = c_int::try_from(input.len()).unwrap();
648
649        let mut outlen = 0;
650
651        cvt(ffi::EVP_CipherUpdate(
652            self.as_ptr(),
653            output.map_or(ptr::null_mut(), |b| b.as_mut_ptr()),
654            &mut outlen,
655            input.as_ptr(),
656            inlen,
657        ))?;
658
659        Ok(outlen as usize)
660    }
661
662    /// Like [`Self::cipher_update`] except that it appends output to a [`Vec`].
663    pub fn cipher_update_vec(
664        &mut self,
665        input: &[u8],
666        output: &mut Vec<u8>,
667    ) -> Result<usize, ErrorStack> {
668        let base = output.len();
669        output.resize(base + self.cipher_update_output_size(input.len()), 0);
670        let len = self.cipher_update(input, Some(&mut output[base..]))?;
671        output.truncate(base + len);
672
673        Ok(len)
674    }
675
676    /// Like [`Self::cipher_update`] except that it writes output into the
677    /// `data` buffer. The `inlen` parameter specifies the number of bytes in
678    /// `data` that are considered the input. For streaming ciphers, the size of
679    /// `data` must be at least the input size. Otherwise, it must be at least
680    /// an additional block size larger.
681    ///
682    /// Note: Use [`Self::cipher_update`] with no output argument to write AAD.
683    ///
684    /// # Panics
685    ///
686    /// This function panics if the input size cannot be represented as `int` or
687    /// exceeds the buffer size, or if the output buffer does not contain enough
688    /// additional space.
689    #[corresponds(EVP_CipherUpdate)]
690    pub fn cipher_update_inplace(
691        &mut self,
692        data: &mut [u8],
693        inlen: usize,
694    ) -> Result<usize, ErrorStack> {
695        assert!(inlen <= data.len(), "Input size may not exceed buffer size");
696        let min_output_size = self.cipher_update_output_size(inlen);
697        assert!(
698            data.len() >= min_output_size,
699            "Output buffer size must be at least {} bytes.",
700            min_output_size
701        );
702
703        let inlen = c_int::try_from(inlen).unwrap();
704        let mut outlen = 0;
705        unsafe {
706            cvt(ffi::EVP_CipherUpdate(
707                self.as_ptr(),
708                data.as_mut_ptr(),
709                &mut outlen,
710                data.as_ptr(),
711                inlen,
712            ))
713        }?;
714
715        Ok(outlen as usize)
716    }
717
718    /// Finalizes the encryption or decryption process.
719    ///
720    /// Any remaining data will be written to the output buffer.
721    ///
722    /// Returns the number of bytes written to `output`.
723    ///
724    /// # Panics
725    ///
726    /// Panics if `output` is smaller than the cipher's block size.
727    #[corresponds(EVP_CipherFinal)]
728    pub fn cipher_final(&mut self, output: &mut [u8]) -> Result<usize, ErrorStack> {
729        let block_size = self.block_size();
730        if block_size > 1 {
731            assert!(output.len() >= block_size);
732        }
733
734        unsafe { self.cipher_final_unchecked(output) }
735    }
736
737    /// Finalizes the encryption or decryption process.
738    ///
739    /// Any remaining data will be written to the output buffer.
740    ///
741    /// Returns the number of bytes written to `output`.
742    ///
743    /// This function is the same as [`Self::cipher_final`] but with
744    /// the output buffer size check removed.
745    ///
746    /// # Safety
747    ///
748    /// The caller is expected to provide `output` buffer
749    /// large enough to contain correct number of bytes. For streaming
750    /// ciphers the output buffer can be empty, for block ciphers the
751    /// output buffer should be at least as big as the block.
752    #[corresponds(EVP_CipherFinal)]
753    pub unsafe fn cipher_final_unchecked(
754        &mut self,
755        output: &mut [u8],
756    ) -> Result<usize, ErrorStack> {
757        let mut outl = 0;
758
759        cvt(ffi::EVP_CipherFinal(
760            self.as_ptr(),
761            output.as_mut_ptr(),
762            &mut outl,
763        ))?;
764
765        Ok(outl as usize)
766    }
767
768    /// Like [`Self::cipher_final`] except that it appends output to a [`Vec`].
769    pub fn cipher_final_vec(&mut self, output: &mut Vec<u8>) -> Result<usize, ErrorStack> {
770        let base = output.len();
771        output.resize(base + self.block_size(), 0);
772        let len = self.cipher_final(&mut output[base..])?;
773        output.truncate(base + len);
774
775        Ok(len)
776    }
777}
778
779#[cfg(test)]
780mod test {
781    use super::*;
782    use crate::{cipher::Cipher, rand::rand_bytes};
783    #[cfg(not(any(boringssl, awslc)))]
784    use std::slice;
785
786    #[test]
787    #[cfg(not(any(boringssl, awslc)))]
788    fn seal_open() {
789        let private_pem = include_bytes!("../test/rsa.pem");
790        let public_pem = include_bytes!("../test/rsa.pem.pub");
791        let private_key = PKey::private_key_from_pem(private_pem).unwrap();
792        let public_key = PKey::public_key_from_pem(public_pem).unwrap();
793        let cipher = Cipher::aes_256_cbc();
794        let secret = b"My secret message";
795
796        let mut ctx = CipherCtx::new().unwrap();
797        let mut encrypted_key = vec![];
798        let mut iv = vec![0; cipher.iv_length()];
799        let mut encrypted = vec![];
800        ctx.seal_init(
801            Some(cipher),
802            &[public_key],
803            slice::from_mut(&mut encrypted_key),
804            Some(&mut iv),
805        )
806        .unwrap();
807        ctx.cipher_update_vec(secret, &mut encrypted).unwrap();
808        ctx.cipher_final_vec(&mut encrypted).unwrap();
809
810        let mut decrypted = vec![];
811        ctx.open_init(Some(cipher), &encrypted_key, Some(&iv), Some(&private_key))
812            .unwrap();
813        ctx.cipher_update_vec(&encrypted, &mut decrypted).unwrap();
814        ctx.cipher_final_vec(&mut decrypted).unwrap();
815
816        assert_eq!(secret, &decrypted[..]);
817    }
818
819    fn aes_128_cbc(cipher: &CipherRef) {
820        // from https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf
821        let key = hex::decode("2b7e151628aed2a6abf7158809cf4f3c").unwrap();
822        let iv = hex::decode("000102030405060708090a0b0c0d0e0f").unwrap();
823        let pt = hex::decode("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51")
824            .unwrap();
825        let ct = hex::decode("7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b2")
826            .unwrap();
827
828        let mut ctx = CipherCtx::new().unwrap();
829
830        ctx.encrypt_init(Some(cipher), Some(&key), Some(&iv))
831            .unwrap();
832        ctx.set_padding(false);
833
834        let mut buf = vec![];
835        ctx.cipher_update_vec(&pt, &mut buf).unwrap();
836        ctx.cipher_final_vec(&mut buf).unwrap();
837
838        assert_eq!(buf, ct);
839
840        ctx.decrypt_init(Some(cipher), Some(&key), Some(&iv))
841            .unwrap();
842        ctx.set_padding(false);
843
844        let mut buf = vec![];
845        ctx.cipher_update_vec(&ct, &mut buf).unwrap();
846        ctx.cipher_final_vec(&mut buf).unwrap();
847
848        assert_eq!(buf, pt);
849    }
850
851    #[test]
852    #[cfg(ossl300)]
853    fn fetched_aes_128_cbc() {
854        let cipher = Cipher::fetch(None, "AES-128-CBC", None).unwrap();
855        aes_128_cbc(&cipher);
856    }
857
858    #[test]
859    fn default_aes_128_cbc() {
860        let cipher = Cipher::aes_128_cbc();
861        aes_128_cbc(cipher);
862    }
863
864    #[cfg(not(boringssl))]
865    #[test]
866    fn default_aes_128_ccm() {
867        // from https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/mac/ccmtestvectors.zip
868        let cipher = Cipher::aes_128_ccm();
869        aes_ccm(
870            cipher,
871            "26511fb51fcfa75cb4b44da75a6e5a0e",
872            "ea98ec44f5a86715014783172e",
873            "4da40b80579c1d9a5309f7efecb7c059a2f914511ca5fc10",
874            "e4692b9f06b666c7451b146c8aeb07a6e30c629d28065c3dde5940325b14b810",
875            "1bf0ba0ebb20d8edba59f29a9371750c9c714078f73c335d",
876            "2f1322ac69b848b001476323aed84c47",
877        );
878    }
879
880    #[cfg(not(boringssl))]
881    #[test]
882    fn default_aes_192_ccm() {
883        // from https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/mac/ccmtestvectors.zip
884        let cipher = Cipher::aes_192_ccm();
885        aes_ccm(
886            cipher,
887            "26511fb51fcfa75cb4b44da75a6e5a0eb8d9c8f3b906f886",
888            "ea98ec44f5a86715014783172e",
889            "4da40b80579c1d9a5309f7efecb7c059a2f914511ca5fc10",
890            "e4692b9f06b666c7451b146c8aeb07a6e30c629d28065c3dde5940325b14b810",
891            "30c154c616946eccc2e241d336ad33720953e449a0e6b0f0",
892            "dbf8e9464909bdf337e48093c082a10b",
893        );
894    }
895
896    #[cfg(not(boringssl))]
897    #[test]
898    fn default_aes_256_ccm() {
899        // from https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/mac/ccmtestvectors.zip
900        let cipher = Cipher::aes_256_ccm();
901        aes_ccm(
902            cipher,
903            "314a202f836f9f257e22d8c11757832ae5131d357a72df88f3eff0ffcee0da4e",
904            "3542fbe0f59a6d5f3abf619b7d",
905            "c5b3d71312ea14f2f8fae5bd1a453192b6604a45db75c5ed",
906            "dd4531f158a2fa3bc8a339f770595048f4a42bc1b03f2e824efc6ba4985119d8",
907            "39c2e8f6edfe663b90963b98eb79e2d4f7f28a5053ae8881",
908            "567a6b4426f1667136bed4a5e32a2bc1",
909        );
910    }
911
912    #[cfg(not(boringssl))]
913    fn aes_ccm(
914        cipher: &CipherRef,
915        key: &'static str,
916        iv: &'static str,
917        pt: &'static str,
918        aad: &'static str,
919        ct: &'static str,
920        tag: &'static str,
921    ) {
922        let key = hex::decode(key).unwrap();
923        let iv = hex::decode(iv).unwrap();
924        let pt = hex::decode(pt).unwrap();
925        let ct = hex::decode(ct).unwrap();
926        let aad = hex::decode(aad).unwrap();
927        let tag = hex::decode(tag).unwrap();
928
929        let mut ctx = CipherCtx::new().unwrap();
930
931        ctx.encrypt_init(Some(cipher), None, None).unwrap();
932        ctx.set_iv_length(iv.len()).unwrap();
933        ctx.set_tag_length(tag.len()).unwrap();
934        ctx.encrypt_init(None, Some(&key), Some(&iv)).unwrap();
935        ctx.set_data_len(pt.len()).unwrap();
936
937        let mut buf = vec![];
938        ctx.cipher_update(&aad, None).unwrap();
939        ctx.cipher_update_vec(&pt, &mut buf).unwrap();
940        ctx.cipher_final_vec(&mut buf).unwrap();
941        assert_eq!(buf, ct);
942
943        let mut out_tag = vec![0u8; tag.len()];
944        ctx.tag(&mut out_tag).unwrap();
945        assert_eq!(tag, out_tag);
946
947        ctx.decrypt_init(Some(cipher), None, None).unwrap();
948        ctx.set_iv_length(iv.len()).unwrap();
949        ctx.set_tag(&tag).unwrap();
950        ctx.decrypt_init(None, Some(&key), Some(&iv)).unwrap();
951        ctx.set_data_len(pt.len()).unwrap();
952
953        let mut buf = vec![];
954        ctx.cipher_update(&aad, None).unwrap();
955        ctx.cipher_update_vec(&ct, &mut buf).unwrap();
956        // Some older libraries don't support calling EVP_CipherFinal/EVP_DecryptFinal for CCM
957        // https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption#Authenticated_Decryption_using_CCM_mode
958        #[cfg(any(ossl111, awslc, boringssl))]
959        ctx.cipher_final_vec(&mut buf).unwrap();
960
961        assert_eq!(buf, pt);
962    }
963
964    #[cfg(not(any(boringssl, awslc)))]
965    #[test]
966    fn default_aes_128_xts() {
967        // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/aes/XTSTestVectors.zip
968        let cipher = Cipher::aes_128_xts();
969        aes_xts(
970            cipher,
971            "a1b90cba3f06ac353b2c343876081762090923026e91771815f29dab01932f2f",
972            "4faef7117cda59c66e4b92013e768ad5",
973            "ebabce95b14d3c8d6fb350390790311c",
974            "778ae8b43cb98d5a825081d5be471c63",
975        );
976    }
977
978    #[cfg(not(boringssl))]
979    #[test]
980    fn default_aes_256_xts() {
981        // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/aes/XTSTestVectors.zip
982        let cipher = Cipher::aes_256_xts();
983        aes_xts(cipher, "1ea661c58d943a0e4801e42f4b0947149e7f9f8e3e68d0c7505210bd311a0e7cd6e13ffdf2418d8d1911c004cda58da3d619b7e2b9141e58318eea392cf41b08", "adf8d92627464ad2f0428e84a9f87564", "2eedea52cd8215e1acc647e810bbc3642e87287f8d2e57e36c0a24fbc12a202e", "cbaad0e2f6cea3f50b37f934d46a9b130b9d54f07e34f36af793e86f73c6d7db");
984    }
985
986    #[cfg(not(boringssl))]
987    fn aes_xts(
988        cipher: &CipherRef,
989        key: &'static str,
990        i: &'static str,
991        pt: &'static str,
992        ct: &'static str,
993    ) {
994        let key = hex::decode(key).unwrap();
995        let i = hex::decode(i).unwrap();
996        let pt = hex::decode(pt).unwrap();
997        let ct = hex::decode(ct).unwrap();
998
999        let mut ctx = CipherCtx::new().unwrap();
1000        ctx.encrypt_init(Some(cipher), Some(&key), Some(&i))
1001            .unwrap();
1002        let mut buf = vec![];
1003        ctx.cipher_update_vec(&pt, &mut buf).unwrap();
1004        ctx.cipher_final_vec(&mut buf).unwrap();
1005
1006        assert_eq!(ct, buf);
1007
1008        ctx.decrypt_init(Some(cipher), Some(&key), Some(&i))
1009            .unwrap();
1010        let mut buf = vec![];
1011        ctx.cipher_update_vec(&ct, &mut buf).unwrap();
1012        ctx.cipher_final_vec(&mut buf).unwrap();
1013
1014        assert_eq!(pt, buf);
1015    }
1016
1017    #[test]
1018    fn test_stream_ciphers() {
1019        #[cfg(not(boringssl))]
1020        {
1021            test_stream_cipher(Cipher::aes_128_cfb1());
1022            test_stream_cipher(Cipher::aes_128_cfb8());
1023            test_stream_cipher(Cipher::aes_128_cfb128());
1024            test_stream_cipher(Cipher::aes_192_cfb1());
1025            test_stream_cipher(Cipher::aes_192_cfb8());
1026            test_stream_cipher(Cipher::aes_192_cfb128());
1027            test_stream_cipher(Cipher::aes_256_cfb1());
1028            test_stream_cipher(Cipher::aes_256_cfb8());
1029            test_stream_cipher(Cipher::aes_256_cfb128());
1030        }
1031        test_stream_cipher(Cipher::aes_192_ctr());
1032        test_stream_cipher(Cipher::aes_256_ctr());
1033    }
1034
1035    fn test_stream_cipher(cipher: &'static CipherRef) {
1036        let mut key = vec![0; cipher.key_length()];
1037        rand_bytes(&mut key).unwrap();
1038        let mut iv = vec![0; cipher.iv_length()];
1039        rand_bytes(&mut iv).unwrap();
1040
1041        let mut ctx = CipherCtx::new().unwrap();
1042
1043        ctx.encrypt_init(Some(cipher), Some(&key), Some(&iv))
1044            .unwrap();
1045        ctx.set_padding(false);
1046
1047        assert_eq!(
1048            1,
1049            cipher.block_size(),
1050            "Need a stream cipher, not a block cipher"
1051        );
1052
1053        // update cipher with non-full block
1054        // this is a streaming cipher so the number of output bytes
1055        // will be the same as the number of input bytes
1056        let mut output = vec![0; 32];
1057        let outlen = ctx
1058            .cipher_update(&[1; 15], Some(&mut output[0..15]))
1059            .unwrap();
1060        assert_eq!(15, outlen);
1061
1062        // update cipher with missing bytes from the previous block
1063        // as previously it will output the same number of bytes as
1064        // the input
1065        let outlen = ctx
1066            .cipher_update(&[1; 17], Some(&mut output[15..]))
1067            .unwrap();
1068        assert_eq!(17, outlen);
1069
1070        ctx.cipher_final_vec(&mut vec![0; 0]).unwrap();
1071
1072        // encrypt again, but use in-place encryption this time
1073        // First reset the IV
1074        ctx.encrypt_init(None, None, Some(&iv)).unwrap();
1075        ctx.set_padding(false);
1076        let mut data_inplace: [u8; 32] = [1; 32];
1077        let outlen = ctx
1078            .cipher_update_inplace(&mut data_inplace[0..15], 15)
1079            .unwrap();
1080        assert_eq!(15, outlen);
1081
1082        let outlen = ctx
1083            .cipher_update_inplace(&mut data_inplace[15..32], 17)
1084            .unwrap();
1085        assert_eq!(17, outlen);
1086
1087        ctx.cipher_final(&mut [0u8; 0]).unwrap();
1088
1089        // Check that the resulting data is encrypted in the same manner
1090        assert_eq!(data_inplace.as_slice(), output.as_slice());
1091
1092        // try to decrypt
1093        ctx.decrypt_init(Some(cipher), Some(&key), Some(&iv))
1094            .unwrap();
1095        ctx.set_padding(false);
1096
1097        // update cipher with non-full block
1098        // expect that the output for stream cipher will contain
1099        // the same number of bytes as the input
1100        let mut output_decrypted = vec![0; 32];
1101        let outlen = ctx
1102            .cipher_update(&output[0..15], Some(&mut output_decrypted[0..15]))
1103            .unwrap();
1104        assert_eq!(15, outlen);
1105
1106        let outlen = ctx
1107            .cipher_update(&output[15..], Some(&mut output_decrypted[15..]))
1108            .unwrap();
1109        assert_eq!(17, outlen);
1110
1111        ctx.cipher_final_vec(&mut vec![0; 0]).unwrap();
1112        // check if the decrypted blocks are the same as input (all ones)
1113        assert_eq!(output_decrypted, vec![1; 32]);
1114
1115        // decrypt again, but now the output in-place
1116        ctx.decrypt_init(None, None, Some(&iv)).unwrap();
1117        ctx.set_padding(false);
1118
1119        let outlen = ctx.cipher_update_inplace(&mut output[0..15], 15).unwrap();
1120        assert_eq!(15, outlen);
1121
1122        let outlen = ctx.cipher_update_inplace(&mut output[15..], 17).unwrap();
1123        assert_eq!(17, outlen);
1124
1125        ctx.cipher_final_vec(&mut vec![0; 0]).unwrap();
1126        assert_eq!(output_decrypted, output);
1127    }
1128
1129    #[test]
1130    #[should_panic(expected = "Output buffer size should be at least 33 bytes.")]
1131    fn full_block_updates_aes_128() {
1132        output_buffer_too_small(Cipher::aes_128_cbc());
1133    }
1134
1135    #[test]
1136    #[should_panic(expected = "Output buffer size should be at least 33 bytes.")]
1137    fn full_block_updates_aes_256() {
1138        output_buffer_too_small(Cipher::aes_256_cbc());
1139    }
1140
1141    #[test]
1142    #[should_panic(expected = "Output buffer size should be at least 17 bytes.")]
1143    fn full_block_updates_3des() {
1144        output_buffer_too_small(Cipher::des_ede3_cbc());
1145    }
1146
1147    fn output_buffer_too_small(cipher: &'static CipherRef) {
1148        let mut key = vec![0; cipher.key_length()];
1149        rand_bytes(&mut key).unwrap();
1150        let mut iv = vec![0; cipher.iv_length()];
1151        rand_bytes(&mut iv).unwrap();
1152
1153        let mut ctx = CipherCtx::new().unwrap();
1154
1155        ctx.encrypt_init(Some(cipher), Some(&key), Some(&iv))
1156            .unwrap();
1157        ctx.set_padding(false);
1158
1159        let block_size = cipher.block_size();
1160        assert!(block_size > 1, "Need a block cipher, not a stream cipher");
1161
1162        ctx.cipher_update(&vec![0; block_size + 1], Some(&mut vec![0; block_size - 1]))
1163            .unwrap();
1164    }
1165
1166    #[cfg(ossl110)]
1167    fn cipher_wrap_test(cipher: &CipherRef, pt: &str, ct: &str, key: &str, iv: Option<&str>) {
1168        let pt = hex::decode(pt).unwrap();
1169        let key = hex::decode(key).unwrap();
1170        let expected = hex::decode(ct).unwrap();
1171        let iv = iv.map(|v| hex::decode(v).unwrap());
1172        let padding = 8 - pt.len() % 8;
1173        let mut computed = vec![0; pt.len() + padding + cipher.block_size() * 2];
1174        let mut ctx = CipherCtx::new().unwrap();
1175
1176        ctx.set_flags(CipherCtxFlags::FLAG_WRAP_ALLOW);
1177        ctx.encrypt_init(Some(cipher), Some(&key), iv.as_deref())
1178            .unwrap();
1179
1180        let count = ctx.cipher_update(&pt, Some(&mut computed)).unwrap();
1181        let rest = ctx.cipher_final(&mut computed[count..]).unwrap();
1182        computed.truncate(count + rest);
1183
1184        if computed != expected {
1185            println!("Computed: {}", hex::encode(&computed));
1186            println!("Expected: {}", hex::encode(&expected));
1187            if computed.len() != expected.len() {
1188                println!(
1189                    "Lengths differ: {} in computed vs {} expected",
1190                    computed.len(),
1191                    expected.len()
1192                );
1193            }
1194            panic!("test failure");
1195        }
1196    }
1197
1198    #[test]
1199    #[cfg(ossl110)]
1200    fn test_aes128_wrap() {
1201        let pt = "00112233445566778899aabbccddeeff";
1202        let ct = "7940ff694448b5bb5139c959a4896832e55d69aa04daa27e";
1203        let key = "2b7e151628aed2a6abf7158809cf4f3c";
1204        let iv = "0001020304050607";
1205
1206        cipher_wrap_test(Cipher::aes_128_wrap(), pt, ct, key, Some(iv));
1207    }
1208
1209    #[test]
1210    #[cfg(ossl110)]
1211    fn test_aes128_wrap_default_iv() {
1212        let pt = "00112233445566778899aabbccddeeff";
1213        let ct = "38f1215f0212526f8a70b51955b9fbdc9fe3041d9832306e";
1214        let key = "2b7e151628aed2a6abf7158809cf4f3c";
1215
1216        cipher_wrap_test(Cipher::aes_128_wrap(), pt, ct, key, None);
1217    }
1218
1219    #[test]
1220    #[cfg(ossl110)]
1221    fn test_aes128_wrap_pad() {
1222        let pt = "00112233445566778899aabbccddee";
1223        let ct = "f13998f5ab32ef82a1bdbcbe585e1d837385b529572a1e1b";
1224        let key = "2b7e151628aed2a6abf7158809cf4f3c";
1225        let iv = "00010203";
1226
1227        cipher_wrap_test(Cipher::aes_128_wrap_pad(), pt, ct, key, Some(iv));
1228    }
1229
1230    #[test]
1231    #[cfg(ossl110)]
1232    fn test_aes128_wrap_pad_default_iv() {
1233        let pt = "00112233445566778899aabbccddee";
1234        let ct = "3a501085fb8cf66f4186b7df851914d471ed823411598add";
1235        let key = "2b7e151628aed2a6abf7158809cf4f3c";
1236
1237        cipher_wrap_test(Cipher::aes_128_wrap_pad(), pt, ct, key, None);
1238    }
1239
1240    #[test]
1241    #[cfg(ossl110)]
1242    fn test_aes192_wrap() {
1243        let pt = "9f6dee187d35302116aecbfd059657efd9f7589c4b5e7f5b";
1244        let ct = "83b89142dfeeb4871e078bfb81134d33e23fedc19b03a1cf689973d3831b6813";
1245        let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b";
1246        let iv = "0001020304050607";
1247
1248        cipher_wrap_test(Cipher::aes_192_wrap(), pt, ct, key, Some(iv));
1249    }
1250
1251    #[test]
1252    #[cfg(ossl110)]
1253    fn test_aes192_wrap_default_iv() {
1254        let pt = "9f6dee187d35302116aecbfd059657efd9f7589c4b5e7f5b";
1255        let ct = "c02c2cf11505d3e4851030d5534cbf5a1d7eca7ba8839adbf239756daf1b43e6";
1256        let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b";
1257
1258        cipher_wrap_test(Cipher::aes_192_wrap(), pt, ct, key, None);
1259    }
1260
1261    #[test]
1262    #[cfg(ossl110)]
1263    fn test_aes192_wrap_pad() {
1264        let pt = "00112233445566778899aabbccddee";
1265        let ct = "b4f6bb167ef7caf061a74da82b36ad038ca057ab51e98d3a";
1266        let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b";
1267        let iv = "00010203";
1268
1269        cipher_wrap_test(Cipher::aes_192_wrap_pad(), pt, ct, key, Some(iv));
1270    }
1271
1272    #[test]
1273    #[cfg(ossl110)]
1274    fn test_aes192_wrap_pad_default_iv() {
1275        let pt = "00112233445566778899aabbccddee";
1276        let ct = "b2c37a28cc602753a7c944a4c2555a2df9c98b2eded5312e";
1277        let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b";
1278
1279        cipher_wrap_test(Cipher::aes_192_wrap_pad(), pt, ct, key, None);
1280    }
1281
1282    #[test]
1283    #[cfg(ossl110)]
1284    fn test_aes256_wrap() {
1285        let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51";
1286        let ct = "cc05da2a7f56f7dd0c144231f90bce58648fa20a8278f5a6b7d13bba6aa57a33229d4333866b7fd6";
1287        let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4";
1288        let iv = "0001020304050607";
1289
1290        cipher_wrap_test(Cipher::aes_256_wrap(), pt, ct, key, Some(iv));
1291    }
1292
1293    #[test]
1294    #[cfg(ossl110)]
1295    fn test_aes256_wrap_default_iv() {
1296        let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51";
1297        let ct = "0b24f068b50e52bc6987868411c36e1b03900866ed12af81eb87cef70a8d1911731c1d7abf789d88";
1298        let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4";
1299
1300        cipher_wrap_test(Cipher::aes_256_wrap(), pt, ct, key, None);
1301    }
1302
1303    #[test]
1304    #[cfg(ossl110)]
1305    fn test_aes256_wrap_pad() {
1306        let pt = "00112233445566778899aabbccddee";
1307        let ct = "91594e044ccc06130d60e6c84a996aa4f96a9faff8c5f6e7";
1308        let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4";
1309        let iv = "00010203";
1310
1311        cipher_wrap_test(Cipher::aes_256_wrap_pad(), pt, ct, key, Some(iv));
1312    }
1313
1314    #[test]
1315    #[cfg(ossl110)]
1316    fn test_aes256_wrap_pad_default_iv() {
1317        let pt = "00112233445566778899aabbccddee";
1318        let ct = "dc3c166a854afd68aea624a4272693554bf2e4fcbae602cd";
1319        let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4";
1320
1321        cipher_wrap_test(Cipher::aes_256_wrap_pad(), pt, ct, key, None);
1322    }
1323
1324    #[test]
1325    #[cfg(ossl110)]
1326    fn test_aes_wrap_pad_cipher_update_vec_buffer_size() {
1327        let cipher = Cipher::aes_256_wrap_pad();
1328        let key = [0u8; 32];
1329        let iv = [0u8; 4];
1330        let pt = [0u8; 9];
1331
1332        let mut ctx = CipherCtx::new().unwrap();
1333        ctx.set_flags(CipherCtxFlags::FLAG_WRAP_ALLOW);
1334        ctx.encrypt_init(Some(cipher), Some(&key), Some(&iv))
1335            .unwrap();
1336
1337        let mut out = vec![];
1338        let len = ctx.cipher_update_vec(&pt, &mut out).unwrap();
1339        // The vec must be large enough to fit the amount of data we wrote.
1340        assert!(out.capacity() >= len);
1341        assert_eq!(len, 24);
1342    }
1343
1344    #[test]
1345    #[cfg(ossl110)]
1346    #[should_panic(expected = "Output buffer size must be at least 24 bytes.")]
1347    fn test_aes_wrap_pad_cipher_update_inplace_buffer_size() {
1348        let cipher = Cipher::aes_256_wrap_pad();
1349        let key = [0u8; 32];
1350        let iv = [0u8; 4];
1351
1352        let mut ctx = CipherCtx::new().unwrap();
1353        ctx.set_flags(CipherCtxFlags::FLAG_WRAP_ALLOW);
1354        ctx.encrypt_init(Some(cipher), Some(&key), Some(&iv))
1355            .unwrap();
1356
1357        // 9 bytes of input would produce 24 bytes of wrap-pad output, but the
1358        // previous bound (inlen + block_size = 17) would have let this through
1359        // and let OpenSSL write past the end of the slice.
1360        let mut buf = [0u8; 17];
1361        let _ = ctx.cipher_update_inplace(&mut buf, 9);
1362    }
1363}