Skip to main content

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