Skip to main content

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