boring_imp/
symm.rs

1//! High level interface to certain symmetric ciphers.
2//!
3//! # Examples
4//!
5//! Encrypt data in AES128 CBC mode
6//!
7//! ```
8//! use boring::symm::{encrypt, Cipher};
9//!
10//! let cipher = Cipher::aes_128_cbc();
11//! let data = b"Some Crypto Text";
12//! let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F";
13//! let iv = b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07";
14//! let ciphertext = encrypt(
15//!     cipher,
16//!     key,
17//!     Some(iv),
18//!     data).unwrap();
19//!
20//! assert_eq!(
21//!     b"\xB4\xB9\xE7\x30\xD6\xD6\xF7\xDE\x77\x3F\x1C\xFF\xB3\x3E\x44\x5A\x91\xD7\x27\x62\x87\x4D\
22//!       \xFB\x3C\x5E\xC4\x59\x72\x4A\xF4\x7C\xA1",
23//!     &ciphertext[..]);
24//! ```
25//!
26//! Encrypting an asymmetric key with a symmetric cipher
27//!
28//! ```
29//! use boring::rsa::{Padding, Rsa};
30//! use boring::symm::Cipher;
31//!
32//! // Generate keypair and encrypt private key:
33//! let keypair = Rsa::generate(2048).unwrap();
34//! let cipher = Cipher::aes_256_cbc();
35//! let pubkey_pem = keypair.public_key_to_pem_pkcs1().unwrap();
36//! let privkey_pem = keypair.private_key_to_pem_passphrase(cipher, b"Rust").unwrap();
37//! // pubkey_pem and privkey_pem could be written to file here.
38//!
39//! // Load private and public key from string:
40//! let pubkey = Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap();
41//! let privkey = Rsa::private_key_from_pem_passphrase(&privkey_pem, b"Rust").unwrap();
42//!
43//! // Use the asymmetric keys to encrypt and decrypt a short message:
44//! let msg = b"Foo bar";
45//! let mut encrypted = vec![0; pubkey.size() as usize];
46//! let mut decrypted = vec![0; privkey.size() as usize];
47//! let len = pubkey.public_encrypt(msg, &mut encrypted, Padding::PKCS1).unwrap();
48//! assert!(len > msg.len());
49//! let len = privkey.private_decrypt(&encrypted, &mut decrypted, Padding::PKCS1).unwrap();
50//! let output_string = String::from_utf8(decrypted[..len].to_vec()).unwrap();
51//! assert_eq!("Foo bar", output_string);
52//! println!("Decrypted: '{}'", output_string);
53//! ```
54
55use crate::ffi;
56use libc::{c_int, c_uint};
57use std::cmp;
58use std::ptr;
59
60use crate::error::ErrorStack;
61use crate::nid::Nid;
62use crate::{cvt, cvt_p};
63
64#[derive(Copy, Clone)]
65pub enum Mode {
66    Encrypt,
67    Decrypt,
68}
69
70/// Represents a particular cipher algorithm.
71///
72/// See OpenSSL doc at [`EVP_EncryptInit`] for more information on each algorithms.
73///
74/// [`EVP_EncryptInit`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_EncryptInit.html
75#[derive(Copy, Clone, PartialEq, Eq)]
76pub struct Cipher(*const ffi::EVP_CIPHER);
77
78impl Cipher {
79    /// Looks up the cipher for a certain nid.
80    ///
81    /// This corresponds to [`EVP_get_cipherbynid`]
82    ///
83    /// [`EVP_get_cipherbynid`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_get_cipherbyname.html
84    pub fn from_nid(nid: Nid) -> Option<Cipher> {
85        let ptr = unsafe { ffi::EVP_get_cipherbyname(ffi::OBJ_nid2sn(nid.as_raw())) };
86        if ptr.is_null() {
87            None
88        } else {
89            Some(Cipher(ptr))
90        }
91    }
92
93    pub fn aes_128_ecb() -> Cipher {
94        unsafe { Cipher(ffi::EVP_aes_128_ecb()) }
95    }
96
97    pub fn aes_128_cbc() -> Cipher {
98        unsafe { Cipher(ffi::EVP_aes_128_cbc()) }
99    }
100
101    pub fn aes_128_ctr() -> Cipher {
102        unsafe { Cipher(ffi::EVP_aes_128_ctr()) }
103    }
104
105    pub fn aes_128_gcm() -> Cipher {
106        unsafe { Cipher(ffi::EVP_aes_128_gcm()) }
107    }
108
109    pub fn aes_128_ofb() -> Cipher {
110        unsafe { Cipher(ffi::EVP_aes_128_ofb()) }
111    }
112
113    pub fn aes_192_ecb() -> Cipher {
114        unsafe { Cipher(ffi::EVP_aes_192_ecb()) }
115    }
116
117    pub fn aes_192_cbc() -> Cipher {
118        unsafe { Cipher(ffi::EVP_aes_192_cbc()) }
119    }
120
121    pub fn aes_192_ctr() -> Cipher {
122        unsafe { Cipher(ffi::EVP_aes_192_ctr()) }
123    }
124
125    pub fn aes_192_gcm() -> Cipher {
126        unsafe { Cipher(ffi::EVP_aes_192_gcm()) }
127    }
128
129    pub fn aes_192_ofb() -> Cipher {
130        unsafe { Cipher(ffi::EVP_aes_192_ofb()) }
131    }
132
133    pub fn aes_256_ecb() -> Cipher {
134        unsafe { Cipher(ffi::EVP_aes_256_ecb()) }
135    }
136
137    pub fn aes_256_cbc() -> Cipher {
138        unsafe { Cipher(ffi::EVP_aes_256_cbc()) }
139    }
140
141    pub fn aes_256_ctr() -> Cipher {
142        unsafe { Cipher(ffi::EVP_aes_256_ctr()) }
143    }
144
145    pub fn aes_256_gcm() -> Cipher {
146        unsafe { Cipher(ffi::EVP_aes_256_gcm()) }
147    }
148
149    pub fn aes_256_ofb() -> Cipher {
150        unsafe { Cipher(ffi::EVP_aes_256_ofb()) }
151    }
152
153    pub fn des_cbc() -> Cipher {
154        unsafe { Cipher(ffi::EVP_des_cbc()) }
155    }
156
157    pub fn des_ecb() -> Cipher {
158        unsafe { Cipher(ffi::EVP_des_ecb()) }
159    }
160
161    pub fn des_ede3() -> Cipher {
162        unsafe { Cipher(ffi::EVP_des_ede3()) }
163    }
164
165    pub fn des_ede3_cbc() -> Cipher {
166        unsafe { Cipher(ffi::EVP_des_ede3_cbc()) }
167    }
168
169    pub fn rc4() -> Cipher {
170        unsafe { Cipher(ffi::EVP_rc4()) }
171    }
172
173    /// Creates a `Cipher` from a raw pointer to its OpenSSL type.
174    ///
175    /// # Safety
176    ///
177    /// The caller must ensure the pointer is valid for the `'static` lifetime.
178    pub unsafe fn from_ptr(ptr: *const ffi::EVP_CIPHER) -> Cipher {
179        Cipher(ptr)
180    }
181
182    #[allow(clippy::trivially_copy_pass_by_ref)]
183    pub fn as_ptr(&self) -> *const ffi::EVP_CIPHER {
184        self.0
185    }
186
187    /// Returns the length of keys used with this cipher.
188    #[allow(clippy::trivially_copy_pass_by_ref)]
189    pub fn key_len(&self) -> usize {
190        unsafe { EVP_CIPHER_key_length(self.0) as usize }
191    }
192
193    /// Returns the length of the IV used with this cipher, or `None` if the
194    /// cipher does not use an IV.
195    #[allow(clippy::trivially_copy_pass_by_ref)]
196    pub fn iv_len(&self) -> Option<usize> {
197        unsafe {
198            let len = EVP_CIPHER_iv_length(self.0) as usize;
199            if len == 0 {
200                None
201            } else {
202                Some(len)
203            }
204        }
205    }
206
207    /// Returns the block size of the cipher.
208    ///
209    /// # Note
210    ///
211    /// Stream ciphers such as RC4 have a block size of 1.
212    #[allow(clippy::trivially_copy_pass_by_ref)]
213    pub fn block_size(&self) -> usize {
214        unsafe { EVP_CIPHER_block_size(self.0) as usize }
215    }
216}
217
218unsafe impl Sync for Cipher {}
219unsafe impl Send for Cipher {}
220
221/// Represents a symmetric cipher context.
222///
223/// Padding is enabled by default.
224///
225/// # Examples
226///
227/// Encrypt some plaintext in chunks, then decrypt the ciphertext back into plaintext, in AES 128
228/// CBC mode.
229///
230/// ```
231/// use boring::symm::{Cipher, Mode, Crypter};
232///
233/// let plaintexts: [&[u8]; 2] = [b"Some Stream of", b" Crypto Text"];
234/// let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F";
235/// let iv = b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07";
236/// let data_len = plaintexts.iter().fold(0, |sum, x| sum + x.len());
237///
238/// // Create a cipher context for encryption.
239/// let mut encrypter = Crypter::new(
240///     Cipher::aes_128_cbc(),
241///     Mode::Encrypt,
242///     key,
243///     Some(iv)).unwrap();
244///
245/// let block_size = Cipher::aes_128_cbc().block_size();
246/// let mut ciphertext = vec![0; data_len + block_size];
247///
248/// // Encrypt 2 chunks of plaintexts successively.
249/// let mut count = encrypter.update(plaintexts[0], &mut ciphertext).unwrap();
250/// count += encrypter.update(plaintexts[1], &mut ciphertext[count..]).unwrap();
251/// count += encrypter.finalize(&mut ciphertext[count..]).unwrap();
252/// ciphertext.truncate(count);
253///
254/// assert_eq!(
255///     b"\x0F\x21\x83\x7E\xB2\x88\x04\xAF\xD9\xCC\xE2\x03\x49\xB4\x88\xF6\xC4\x61\x0E\x32\x1C\xF9\
256///       \x0D\x66\xB1\xE6\x2C\x77\x76\x18\x8D\x99",
257///     &ciphertext[..]
258/// );
259///
260///
261/// // Let's pretend we don't know the plaintext, and now decrypt the ciphertext.
262/// let data_len = ciphertext.len();
263/// let ciphertexts = [&ciphertext[..9], &ciphertext[9..]];
264///
265/// // Create a cipher context for decryption.
266/// let mut decrypter = Crypter::new(
267///     Cipher::aes_128_cbc(),
268///     Mode::Decrypt,
269///     key,
270///     Some(iv)).unwrap();
271/// let mut plaintext = vec![0; data_len + block_size];
272///
273/// // Decrypt 2 chunks of ciphertexts successively.
274/// let mut count = decrypter.update(ciphertexts[0], &mut plaintext).unwrap();
275/// count += decrypter.update(ciphertexts[1], &mut plaintext[count..]).unwrap();
276/// count += decrypter.finalize(&mut plaintext[count..]).unwrap();
277/// plaintext.truncate(count);
278///
279/// assert_eq!(b"Some Stream of Crypto Text", &plaintext[..]);
280/// ```
281pub struct Crypter {
282    ctx: *mut ffi::EVP_CIPHER_CTX,
283    block_size: usize,
284}
285
286unsafe impl Sync for Crypter {}
287unsafe impl Send for Crypter {}
288
289impl Crypter {
290    /// Creates a new `Crypter`.  The initialisation vector, `iv`, is not necesarry for certain
291    /// types of `Cipher`.
292    ///
293    /// # Panics
294    ///
295    /// Panics if an IV is required by the cipher but not provided.  Also make sure that the key
296    /// and IV size are appropriate for your cipher.
297    pub fn new(
298        t: Cipher,
299        mode: Mode,
300        key: &[u8],
301        iv: Option<&[u8]>,
302    ) -> Result<Crypter, ErrorStack> {
303        ffi::init();
304
305        unsafe {
306            let ctx = cvt_p(ffi::EVP_CIPHER_CTX_new())?;
307            let crypter = Crypter {
308                ctx,
309                block_size: t.block_size(),
310            };
311
312            let mode = match mode {
313                Mode::Encrypt => 1,
314                Mode::Decrypt => 0,
315            };
316
317            cvt(ffi::EVP_CipherInit_ex(
318                crypter.ctx,
319                t.as_ptr(),
320                ptr::null_mut(),
321                ptr::null_mut(),
322                ptr::null_mut(),
323                mode,
324            ))?;
325
326            assert!(key.len() <= c_int::MAX as usize);
327            cvt(ffi::EVP_CIPHER_CTX_set_key_length(
328                crypter.ctx,
329                key.len() as c_uint,
330            ))?;
331
332            let key = key.as_ptr() as *mut _;
333            let iv = match (iv, t.iv_len()) {
334                (Some(iv), Some(len)) => {
335                    if iv.len() != len {
336                        assert!(iv.len() <= c_int::MAX as usize);
337                        cvt(ffi::EVP_CIPHER_CTX_ctrl(
338                            crypter.ctx,
339                            ffi::EVP_CTRL_GCM_SET_IVLEN,
340                            iv.len() as c_int,
341                            ptr::null_mut(),
342                        ))?;
343                    }
344                    iv.as_ptr() as *mut _
345                }
346                (Some(_), None) | (None, None) => ptr::null_mut(),
347                (None, Some(_)) => panic!("an IV is required for this cipher"),
348            };
349            cvt(ffi::EVP_CipherInit_ex(
350                crypter.ctx,
351                ptr::null(),
352                ptr::null_mut(),
353                key,
354                iv,
355                mode,
356            ))?;
357
358            Ok(crypter)
359        }
360    }
361
362    /// Enables or disables padding.
363    ///
364    /// If padding is disabled, total amount of data encrypted/decrypted must
365    /// be a multiple of the cipher's block size.
366    pub fn pad(&mut self, padding: bool) {
367        unsafe {
368            ffi::EVP_CIPHER_CTX_set_padding(self.ctx, padding as c_int);
369        }
370    }
371
372    /// Sets the tag used to authenticate ciphertext in AEAD ciphers such as AES GCM.
373    ///
374    /// When decrypting cipher text using an AEAD cipher, this must be called before `finalize`.
375    pub fn set_tag(&mut self, tag: &[u8]) -> Result<(), ErrorStack> {
376        unsafe {
377            assert!(tag.len() <= c_int::MAX as usize);
378            // NB: this constant is actually more general than just GCM.
379            cvt(ffi::EVP_CIPHER_CTX_ctrl(
380                self.ctx,
381                ffi::EVP_CTRL_GCM_SET_TAG,
382                tag.len() as c_int,
383                tag.as_ptr() as *mut _,
384            ))
385            .map(|_| ())
386        }
387    }
388
389    /// Sets the length of the authentication tag to generate in AES CCM.
390    ///
391    /// When encrypting with AES CCM, the tag length needs to be explicitly set in order
392    /// to use a value different than the default 12 bytes.
393    pub fn set_tag_len(&mut self, tag_len: usize) -> Result<(), ErrorStack> {
394        unsafe {
395            assert!(tag_len <= c_int::MAX as usize);
396            // NB: this constant is actually more general than just GCM.
397            cvt(ffi::EVP_CIPHER_CTX_ctrl(
398                self.ctx,
399                ffi::EVP_CTRL_GCM_SET_TAG,
400                tag_len as c_int,
401                ptr::null_mut(),
402            ))
403            .map(|_| ())
404        }
405    }
406
407    /// Feeds total plaintext length to the cipher.
408    ///
409    /// The total plaintext or ciphertext length MUST be passed to the cipher when it operates in
410    /// CCM mode.
411    pub fn set_data_len(&mut self, data_len: usize) -> Result<(), ErrorStack> {
412        unsafe {
413            assert!(data_len <= c_int::MAX as usize);
414            let mut len = 0;
415            cvt(ffi::EVP_CipherUpdate(
416                self.ctx,
417                ptr::null_mut(),
418                &mut len,
419                ptr::null_mut(),
420                data_len as c_int,
421            ))
422            .map(|_| ())
423        }
424    }
425
426    /// Feeds Additional Authenticated Data (AAD) through the cipher.
427    ///
428    /// This can only be used with AEAD ciphers such as AES GCM. Data fed in is not encrypted, but
429    /// is factored into the authentication tag. It must be called before the first call to
430    /// `update`.
431    pub fn aad_update(&mut self, input: &[u8]) -> Result<(), ErrorStack> {
432        unsafe {
433            assert!(input.len() <= c_int::MAX as usize);
434            let mut len = 0;
435            cvt(ffi::EVP_CipherUpdate(
436                self.ctx,
437                ptr::null_mut(),
438                &mut len,
439                input.as_ptr(),
440                input.len() as c_int,
441            ))
442            .map(|_| ())
443        }
444    }
445
446    /// Feeds data from `input` through the cipher, writing encrypted/decrypted
447    /// bytes into `output`.
448    ///
449    /// The number of bytes written to `output` is returned. Note that this may
450    /// not be equal to the length of `input`.
451    ///
452    /// # Panics
453    ///
454    /// Panics for stream ciphers if `output.len() < input.len()`.
455    ///
456    /// Panics for block ciphers if `output.len() < input.len() + block_size`,
457    /// where `block_size` is the block size of the cipher (see `Cipher::block_size`).
458    ///
459    /// Panics if `output.len() > c_int::MAX`.
460    pub fn update(&mut self, input: &[u8], output: &mut [u8]) -> Result<usize, ErrorStack> {
461        unsafe {
462            let block_size = if self.block_size > 1 {
463                self.block_size
464            } else {
465                0
466            };
467            assert!(output.len() >= input.len() + block_size);
468            assert!(output.len() <= c_int::MAX as usize);
469            let mut outl = output.len() as c_int;
470            let inl = input.len() as c_int;
471
472            cvt(ffi::EVP_CipherUpdate(
473                self.ctx,
474                output.as_mut_ptr(),
475                &mut outl,
476                input.as_ptr(),
477                inl,
478            ))?;
479
480            Ok(outl as usize)
481        }
482    }
483
484    /// Finishes the encryption/decryption process, writing any remaining data
485    /// to `output`.
486    ///
487    /// The number of bytes written to `output` is returned.
488    ///
489    /// `update` should not be called after this method.
490    ///
491    /// # Panics
492    ///
493    /// Panics for block ciphers if `output.len() < block_size`,
494    /// where `block_size` is the block size of the cipher (see `Cipher::block_size`).
495    pub fn finalize(&mut self, output: &mut [u8]) -> Result<usize, ErrorStack> {
496        unsafe {
497            if self.block_size > 1 {
498                assert!(output.len() >= self.block_size);
499            }
500            let mut outl = cmp::min(output.len(), c_int::MAX as usize) as c_int;
501
502            cvt(ffi::EVP_CipherFinal_ex(
503                self.ctx,
504                output.as_mut_ptr(),
505                &mut outl,
506            ))?;
507
508            Ok(outl as usize)
509        }
510    }
511
512    /// Retrieves the authentication tag used to authenticate ciphertext in AEAD ciphers such
513    /// as AES GCM.
514    ///
515    /// When encrypting data with an AEAD cipher, this must be called after `finalize`.
516    ///
517    /// The size of the buffer indicates the required size of the tag. While some ciphers support a
518    /// range of tag sizes, it is recommended to pick the maximum size. For AES GCM, this is 16
519    /// bytes, for example.
520    pub fn get_tag(&self, tag: &mut [u8]) -> Result<(), ErrorStack> {
521        unsafe {
522            assert!(tag.len() <= c_int::MAX as usize);
523            cvt(ffi::EVP_CIPHER_CTX_ctrl(
524                self.ctx,
525                ffi::EVP_CTRL_GCM_GET_TAG,
526                tag.len() as c_int,
527                tag.as_mut_ptr() as *mut _,
528            ))
529            .map(|_| ())
530        }
531    }
532}
533
534impl Drop for Crypter {
535    fn drop(&mut self) {
536        unsafe {
537            ffi::EVP_CIPHER_CTX_free(self.ctx);
538        }
539    }
540}
541
542/// Encrypts data in one go, and returns the encrypted data.
543///
544/// Data is encrypted using the specified cipher type `t` in encrypt mode with the specified `key`
545/// and initailization vector `iv`. Padding is enabled.
546///
547/// This is a convenient interface to `Crypter` to encrypt all data in one go.  To encrypt a stream
548/// of data increamentally , use `Crypter` instead.
549///
550/// # Examples
551///
552/// Encrypt data in AES128 CBC mode
553///
554/// ```
555/// use boring::symm::{encrypt, Cipher};
556///
557/// let cipher = Cipher::aes_128_cbc();
558/// let data = b"Some Crypto Text";
559/// let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F";
560/// let iv = b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07";
561/// let ciphertext = encrypt(
562///     cipher,
563///     key,
564///     Some(iv),
565///     data).unwrap();
566///
567/// assert_eq!(
568///     b"\xB4\xB9\xE7\x30\xD6\xD6\xF7\xDE\x77\x3F\x1C\xFF\xB3\x3E\x44\x5A\x91\xD7\x27\x62\x87\x4D\
569///       \xFB\x3C\x5E\xC4\x59\x72\x4A\xF4\x7C\xA1",
570///     &ciphertext[..]);
571/// ```
572pub fn encrypt(
573    t: Cipher,
574    key: &[u8],
575    iv: Option<&[u8]>,
576    data: &[u8],
577) -> Result<Vec<u8>, ErrorStack> {
578    cipher(t, Mode::Encrypt, key, iv, data)
579}
580
581/// Decrypts data in one go, and returns the decrypted data.
582///
583/// Data is decrypted using the specified cipher type `t` in decrypt mode with the specified `key`
584/// and initailization vector `iv`. Padding is enabled.
585///
586/// This is a convenient interface to `Crypter` to decrypt all data in one go.  To decrypt a  stream
587/// of data increamentally , use `Crypter` instead.
588///
589/// # Examples
590///
591/// Decrypt data in AES128 CBC mode
592///
593/// ```
594/// use boring::symm::{decrypt, Cipher};
595///
596/// let cipher = Cipher::aes_128_cbc();
597/// let data = b"\xB4\xB9\xE7\x30\xD6\xD6\xF7\xDE\x77\x3F\x1C\xFF\xB3\x3E\x44\x5A\x91\xD7\x27\x62\
598///              \x87\x4D\xFB\x3C\x5E\xC4\x59\x72\x4A\xF4\x7C\xA1";
599/// let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F";
600/// let iv = b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07";
601/// let ciphertext = decrypt(
602///     cipher,
603///     key,
604///     Some(iv),
605///     data).unwrap();
606///
607/// assert_eq!(
608///     b"Some Crypto Text",
609///     &ciphertext[..]);
610/// ```
611pub fn decrypt(
612    t: Cipher,
613    key: &[u8],
614    iv: Option<&[u8]>,
615    data: &[u8],
616) -> Result<Vec<u8>, ErrorStack> {
617    cipher(t, Mode::Decrypt, key, iv, data)
618}
619
620fn cipher(
621    t: Cipher,
622    mode: Mode,
623    key: &[u8],
624    iv: Option<&[u8]>,
625    data: &[u8],
626) -> Result<Vec<u8>, ErrorStack> {
627    let mut c = Crypter::new(t, mode, key, iv)?;
628    let mut out = vec![0; data.len() + t.block_size()];
629    let count = c.update(data, &mut out)?;
630    let rest = c.finalize(&mut out[count..])?;
631    out.truncate(count + rest);
632    Ok(out)
633}
634
635/// Like `encrypt`, but for AEAD ciphers such as AES GCM.
636///
637/// Additional Authenticated Data can be provided in the `aad` field, and the authentication tag
638/// will be copied into the `tag` field.
639///
640/// The size of the `tag` buffer indicates the required size of the tag. While some ciphers support
641/// a range of tag sizes, it is recommended to pick the maximum size. For AES GCM, this is 16 bytes,
642/// for example.
643pub fn encrypt_aead(
644    t: Cipher,
645    key: &[u8],
646    iv: Option<&[u8]>,
647    aad: &[u8],
648    data: &[u8],
649    tag: &mut [u8],
650) -> Result<Vec<u8>, ErrorStack> {
651    let mut c = Crypter::new(t, Mode::Encrypt, key, iv)?;
652    let mut out = vec![0; data.len() + t.block_size()];
653
654    c.aad_update(aad)?;
655    let count = c.update(data, &mut out)?;
656    let rest = c.finalize(&mut out[count..])?;
657    c.get_tag(tag)?;
658    out.truncate(count + rest);
659    Ok(out)
660}
661
662/// Like `decrypt`, but for AEAD ciphers such as AES GCM.
663///
664/// Additional Authenticated Data can be provided in the `aad` field, and the authentication tag
665/// should be provided in the `tag` field.
666pub fn decrypt_aead(
667    t: Cipher,
668    key: &[u8],
669    iv: Option<&[u8]>,
670    aad: &[u8],
671    data: &[u8],
672    tag: &[u8],
673) -> Result<Vec<u8>, ErrorStack> {
674    let mut c = Crypter::new(t, Mode::Decrypt, key, iv)?;
675    let mut out = vec![0; data.len() + t.block_size()];
676
677    c.aad_update(aad)?;
678    let count = c.update(data, &mut out)?;
679
680    c.set_tag(tag)?;
681    let rest = c.finalize(&mut out[count..])?;
682
683    out.truncate(count + rest);
684    Ok(out)
685}
686
687use crate::ffi::{EVP_CIPHER_block_size, EVP_CIPHER_iv_length, EVP_CIPHER_key_length};
688
689#[cfg(test)]
690mod tests {
691    use super::*;
692    use hex::{self, FromHex};
693
694    #[test]
695    fn test_stream_cipher_output() {
696        let key = [0u8; 16];
697        let iv = [0u8; 16];
698        let mut c = super::Crypter::new(
699            super::Cipher::aes_128_ctr(),
700            super::Mode::Encrypt,
701            &key,
702            Some(&iv),
703        )
704        .unwrap();
705
706        assert_eq!(c.update(&[0u8; 15], &mut [0u8; 15]).unwrap(), 15);
707        assert_eq!(c.update(&[0u8; 1], &mut [0u8; 1]).unwrap(), 1);
708        assert_eq!(c.finalize(&mut [0u8; 0]).unwrap(), 0);
709    }
710
711    // Test vectors from FIPS-197:
712    // http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
713    #[test]
714    fn test_aes_256_ecb() {
715        let k0 = [
716            0x00u8, 0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8, 0x07u8, 0x08u8, 0x09u8, 0x0au8,
717            0x0bu8, 0x0cu8, 0x0du8, 0x0eu8, 0x0fu8, 0x10u8, 0x11u8, 0x12u8, 0x13u8, 0x14u8, 0x15u8,
718            0x16u8, 0x17u8, 0x18u8, 0x19u8, 0x1au8, 0x1bu8, 0x1cu8, 0x1du8, 0x1eu8, 0x1fu8,
719        ];
720        let p0 = [
721            0x00u8, 0x11u8, 0x22u8, 0x33u8, 0x44u8, 0x55u8, 0x66u8, 0x77u8, 0x88u8, 0x99u8, 0xaau8,
722            0xbbu8, 0xccu8, 0xddu8, 0xeeu8, 0xffu8,
723        ];
724        let c0 = [
725            0x8eu8, 0xa2u8, 0xb7u8, 0xcau8, 0x51u8, 0x67u8, 0x45u8, 0xbfu8, 0xeau8, 0xfcu8, 0x49u8,
726            0x90u8, 0x4bu8, 0x49u8, 0x60u8, 0x89u8,
727        ];
728        let mut c = super::Crypter::new(
729            super::Cipher::aes_256_ecb(),
730            super::Mode::Encrypt,
731            &k0,
732            None,
733        )
734        .unwrap();
735        c.pad(false);
736        let mut r0 = vec![0; c0.len() + super::Cipher::aes_256_ecb().block_size()];
737        let count = c.update(&p0, &mut r0).unwrap();
738        let rest = c.finalize(&mut r0[count..]).unwrap();
739        r0.truncate(count + rest);
740        assert_eq!(hex::encode(&r0), hex::encode(c0));
741
742        let mut c = super::Crypter::new(
743            super::Cipher::aes_256_ecb(),
744            super::Mode::Decrypt,
745            &k0,
746            None,
747        )
748        .unwrap();
749        c.pad(false);
750        let mut p1 = vec![0; r0.len() + super::Cipher::aes_256_ecb().block_size()];
751        let count = c.update(&r0, &mut p1).unwrap();
752        let rest = c.finalize(&mut p1[count..]).unwrap();
753        p1.truncate(count + rest);
754        assert_eq!(hex::encode(p1), hex::encode(p0));
755    }
756
757    #[test]
758    fn test_aes_256_cbc_decrypt() {
759        let iv = [
760            4_u8, 223_u8, 153_u8, 219_u8, 28_u8, 142_u8, 234_u8, 68_u8, 227_u8, 69_u8, 98_u8,
761            107_u8, 208_u8, 14_u8, 236_u8, 60_u8,
762        ];
763        let data = [
764            143_u8, 210_u8, 75_u8, 63_u8, 214_u8, 179_u8, 155_u8, 241_u8, 242_u8, 31_u8, 154_u8,
765            56_u8, 198_u8, 145_u8, 192_u8, 64_u8, 2_u8, 245_u8, 167_u8, 220_u8, 55_u8, 119_u8,
766            233_u8, 136_u8, 139_u8, 27_u8, 71_u8, 242_u8, 119_u8, 175_u8, 65_u8, 207_u8,
767        ];
768        let ciphered_data = [
769            0x4a_u8, 0x2e_u8, 0xe5_u8, 0x6_u8, 0xbf_u8, 0xcf_u8, 0xf2_u8, 0xd7_u8, 0xea_u8,
770            0x2d_u8, 0xb1_u8, 0x85_u8, 0x6c_u8, 0x93_u8, 0x65_u8, 0x6f_u8,
771        ];
772        let mut cr = super::Crypter::new(
773            super::Cipher::aes_256_cbc(),
774            super::Mode::Decrypt,
775            &data,
776            Some(&iv),
777        )
778        .unwrap();
779        cr.pad(false);
780        let mut unciphered_data = vec![0; data.len() + super::Cipher::aes_256_cbc().block_size()];
781        let count = cr.update(&ciphered_data, &mut unciphered_data).unwrap();
782        let rest = cr.finalize(&mut unciphered_data[count..]).unwrap();
783        unciphered_data.truncate(count + rest);
784
785        let expected_unciphered_data = b"I love turtles.\x01";
786
787        assert_eq!(&unciphered_data, expected_unciphered_data);
788    }
789
790    fn cipher_test(ciphertype: super::Cipher, pt: &str, ct: &str, key: &str, iv: &str) {
791        let pt = Vec::from_hex(pt).unwrap();
792        let ct = Vec::from_hex(ct).unwrap();
793        let key = Vec::from_hex(key).unwrap();
794        let iv = Vec::from_hex(iv).unwrap();
795
796        let computed = super::decrypt(ciphertype, &key, Some(&iv), &ct).unwrap();
797        let expected = pt;
798
799        if computed != expected {
800            println!("Computed: {}", hex::encode(&computed));
801            println!("Expected: {}", hex::encode(&expected));
802            if computed.len() != expected.len() {
803                println!(
804                    "Lengths differ: {} in computed vs {} expected",
805                    computed.len(),
806                    expected.len()
807                );
808            }
809            panic!("test failure");
810        }
811    }
812
813    #[test]
814    fn test_rc4() {
815        let pt = "0000000000000000000000000000000000000000000000000000000000000000000000000000";
816        let ct = "A68686B04D686AA107BD8D4CAB191A3EEC0A6294BC78B60F65C25CB47BD7BB3A48EFC4D26BE4";
817        let key = "97CD440324DA5FD1F7955C1C13B6B466";
818        let iv = "";
819
820        cipher_test(super::Cipher::rc4(), pt, ct, key, iv);
821    }
822
823    #[test]
824    fn test_aes128_ctr() {
825        let pt = "6BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5130C81C46A35CE411\
826                  E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710";
827        let ct = "874D6191B620E3261BEF6864990DB6CE9806F66B7970FDFF8617187BB9FFFDFF5AE4DF3EDBD5D35E\
828                  5B4F09020DB03EAB1E031DDA2FBE03D1792170A0F3009CEE";
829        let key = "2B7E151628AED2A6ABF7158809CF4F3C";
830        let iv = "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF";
831
832        cipher_test(super::Cipher::aes_128_ctr(), pt, ct, key, iv);
833    }
834
835    #[test]
836    fn test_aes128_ofb() {
837        // Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
838
839        let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710";
840        let ct = "3b3fd92eb72dad20333449f8e83cfb4a7789508d16918f03f53c52dac54ed8259740051e9c5fecf64344f7a82260edcc304c6528f659c77866a510d9c1d6ae5e";
841        let key = "2b7e151628aed2a6abf7158809cf4f3c";
842        let iv = "000102030405060708090a0b0c0d0e0f";
843
844        cipher_test(super::Cipher::aes_128_ofb(), pt, ct, key, iv);
845    }
846
847    #[test]
848    fn test_aes192_ctr() {
849        // Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
850
851        let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710";
852        let ct = "1abc932417521ca24f2b0459fe7e6e0b090339ec0aa6faefd5ccc2c6f4ce8e941e36b26bd1ebc670d1bd1d665620abf74f78a7f6d29809585a97daec58c6b050";
853        let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b";
854        let iv = "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
855
856        cipher_test(super::Cipher::aes_192_ctr(), pt, ct, key, iv);
857    }
858
859    #[test]
860    fn test_aes192_ofb() {
861        // Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
862
863        let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710";
864        let ct = "cdc80d6fddf18cab34c25909c99a4174fcc28b8d4c63837c09e81700c11004018d9a9aeac0f6596f559c6d4daf59a5f26d9f200857ca6c3e9cac524bd9acc92a";
865        let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b";
866        let iv = "000102030405060708090a0b0c0d0e0f";
867
868        cipher_test(super::Cipher::aes_192_ofb(), pt, ct, key, iv);
869    }
870
871    #[test]
872    fn test_aes256_ofb() {
873        // Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
874
875        let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710";
876        let ct = "dc7e84bfda79164b7ecd8486985d38604febdc6740d20b3ac88f6ad82a4fb08d71ab47a086e86eedf39d1c5bba97c4080126141d67f37be8538f5a8be740e484";
877        let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4";
878        let iv = "000102030405060708090a0b0c0d0e0f";
879
880        cipher_test(super::Cipher::aes_256_ofb(), pt, ct, key, iv);
881    }
882
883    #[test]
884    fn test_des_cbc() {
885        let pt = "54686973206973206120746573742e";
886        let ct = "6f2867cfefda048a4046ef7e556c7132";
887        let key = "7cb66337f3d3c0fe";
888        let iv = "0001020304050607";
889
890        cipher_test(super::Cipher::des_cbc(), pt, ct, key, iv);
891    }
892
893    #[test]
894    fn test_des_ecb() {
895        let pt = "54686973206973206120746573742e";
896        let ct = "0050ab8aecec758843fe157b4dde938c";
897        let key = "7cb66337f3d3c0fe";
898        let iv = "0001020304050607";
899
900        cipher_test(super::Cipher::des_ecb(), pt, ct, key, iv);
901    }
902
903    #[test]
904    fn test_des_ede3() {
905        let pt = "9994f4c69d40ae4f34ff403b5cf39d4c8207ea5d3e19a5fd";
906        let ct = "9e5c4297d60582f81071ac8ab7d0698d4c79de8b94c519858207ea5d3e19a5fd";
907        let key = "010203040506070801020304050607080102030405060708";
908        let iv = "5cc118306dc702e4";
909
910        cipher_test(super::Cipher::des_ede3(), pt, ct, key, iv);
911    }
912
913    #[test]
914    fn test_des_ede3_cbc() {
915        let pt = "54686973206973206120746573742e";
916        let ct = "6f2867cfefda048a4046ef7e556c7132";
917        let key = "7cb66337f3d3c0fe7cb66337f3d3c0fe7cb66337f3d3c0fe";
918        let iv = "0001020304050607";
919
920        cipher_test(super::Cipher::des_ede3_cbc(), pt, ct, key, iv);
921    }
922
923    #[test]
924    fn test_aes128_gcm() {
925        let key = "0e00c76561d2bd9b40c3c15427e2b08f";
926        let iv = "492cadaccd3ca3fbc9cf9f06eb3325c4e159850b0dbe98199b89b7af528806610b6f63998e1eae80c348e7\
927             4cbb921d8326631631fc6a5d304f39166daf7ea15fa1977f101819adb510b50fe9932e12c5a85aa3fd1e73\
928             d8d760af218be829903a77c63359d75edd91b4f6ed5465a72662f5055999e059e7654a8edc921aa0d496";
929        let pt = "fef03c2d7fb15bf0d2df18007d99f967c878ad59359034f7bb2c19af120685d78e32f6b8b83b032019956c\
930             a9c0195721476b85";
931        let aad = "d8f1163d8c840292a2b2dacf4ac7c36aff8733f18fabb4fa5594544125e03d1e6e5d6d0fd61656c8d8f327\
932             c92839ae5539bb469c9257f109ebff85aad7bd220fdaa95c022dbd0c7bb2d878ad504122c943045d3c5eba\
933             8f1f56c0";
934        let ct = "4f6cf471be7cbd2575cd5a1747aea8fe9dea83e51936beac3e68f66206922060c697ffa7af80ad6bb68f2c\
935             f4fc97416ee52abe";
936        let tag = "e20b6655";
937
938        // this tag is smaller than you'd normally want, but I pulled this test from the part of
939        // the NIST test vectors that cover 4 byte tags.
940        let mut actual_tag = [0; 4];
941        let out = encrypt_aead(
942            Cipher::aes_128_gcm(),
943            &Vec::from_hex(key).unwrap(),
944            Some(&Vec::from_hex(iv).unwrap()),
945            &Vec::from_hex(aad).unwrap(),
946            &Vec::from_hex(pt).unwrap(),
947            &mut actual_tag,
948        )
949        .unwrap();
950        assert_eq!(ct, hex::encode(out));
951        assert_eq!(tag, hex::encode(actual_tag));
952
953        let out = decrypt_aead(
954            Cipher::aes_128_gcm(),
955            &Vec::from_hex(key).unwrap(),
956            Some(&Vec::from_hex(iv).unwrap()),
957            &Vec::from_hex(aad).unwrap(),
958            &Vec::from_hex(ct).unwrap(),
959            &Vec::from_hex(tag).unwrap(),
960        )
961        .unwrap();
962        assert_eq!(pt, hex::encode(out));
963    }
964}