Skip to main content

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