//! Message encryption. //! //! The [`Encrypter`] allows for encryption of data given a public key. The [`Decrypter`] can be //! used with the corresponding private key to decrypt the data. //! //! # Examples //! //! Encrypt and decrypt data given an RSA keypair: //! //! ```rust //! use openssl::encrypt::{Encrypter, Decrypter}; //! use openssl::rsa::{Rsa, Padding}; //! use openssl::pkey::PKey; //! //! // Generate a keypair //! let keypair = Rsa::generate(2048).unwrap(); //! let keypair = PKey::from_rsa(keypair).unwrap(); //! //! let data = b"hello, world!"; //! //! // Encrypt the data with RSA PKCS1 //! let mut encrypter = Encrypter::new(&keypair).unwrap(); //! encrypter.set_rsa_padding(Padding::PKCS1).unwrap(); //! // Create an output buffer //! let buffer_len = encrypter.encrypt_len(data).unwrap(); //! let mut encrypted = vec![0; buffer_len]; //! // Encrypt and truncate the buffer //! let encrypted_len = encrypter.encrypt(data, &mut encrypted).unwrap(); //! encrypted.truncate(encrypted_len); //! //! // Decrypt the data //! let mut decrypter = Decrypter::new(&keypair).unwrap(); //! decrypter.set_rsa_padding(Padding::PKCS1).unwrap(); //! // Create an output buffer //! let buffer_len = decrypter.decrypt_len(&encrypted).unwrap(); //! let mut decrypted = vec![0; buffer_len]; //! // Encrypt and truncate the buffer //! let decrypted_len = decrypter.decrypt(&encrypted, &mut decrypted).unwrap(); //! decrypted.truncate(decrypted_len); //! assert_eq!(&*decrypted, data); //! ``` use libc::{c_int, c_void}; use std::{marker::PhantomData, ptr}; use crate::error::ErrorStack; use crate::hash::MessageDigest; use crate::pkey::{HasPrivate, HasPublic, PKeyRef}; use crate::rsa::Padding; use crate::{cvt, cvt_p}; use foreign_types::ForeignTypeRef; /// A type which encrypts data. pub struct Encrypter<'a> { pctx: *mut ffi::EVP_PKEY_CTX, _p: PhantomData<&'a ()>, } unsafe impl<'a> Sync for Encrypter<'a> {} unsafe impl<'a> Send for Encrypter<'a> {} impl<'a> Drop for Encrypter<'a> { fn drop(&mut self) { unsafe { ffi::EVP_PKEY_CTX_free(self.pctx); } } } impl<'a> Encrypter<'a> { /// Creates a new `Encrypter`. /// /// OpenSSL documentation at [`EVP_PKEY_encrypt_init`]. /// /// [`EVP_PKEY_encrypt_init`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_encrypt_init.html pub fn new(pkey: &'a PKeyRef) -> Result, ErrorStack> where T: HasPublic, { unsafe { ffi::init(); let pctx = cvt_p(ffi::EVP_PKEY_CTX_new(pkey.as_ptr(), ptr::null_mut()))?; let r = ffi::EVP_PKEY_encrypt_init(pctx); if r != 1 { ffi::EVP_PKEY_CTX_free(pctx); return Err(ErrorStack::get()); } Ok(Encrypter { pctx, _p: PhantomData, }) } } /// Returns the RSA padding mode in use. /// /// This is only useful for RSA keys. /// /// This corresponds to `EVP_PKEY_CTX_get_rsa_padding`. pub fn rsa_padding(&self) -> Result { unsafe { let mut pad = 0; cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.pctx, &mut pad)) .map(|_| Padding::from_raw(pad)) } } /// Sets the RSA padding mode. /// /// This is only useful for RSA keys. /// /// This corresponds to [`EVP_PKEY_CTX_set_rsa_padding`]. /// /// [`EVP_PKEY_CTX_set_rsa_padding`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_padding.html pub fn set_rsa_padding(&mut self, padding: Padding) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( self.pctx, padding.as_raw(), )) .map(|_| ()) } } /// Sets the RSA MGF1 algorithm. /// /// This is only useful for RSA keys. /// /// This corresponds to [`EVP_PKEY_CTX_set_rsa_mgf1_md`]. /// /// [`EVP_PKEY_CTX_set_rsa_mgf1_md`]: https://www.openssl.org/docs/manmaster/man7/RSA-PSS.html pub fn set_rsa_mgf1_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_mgf1_md( self.pctx, md.as_ptr() as *mut _, )) .map(|_| ()) } } /// Sets the RSA OAEP algorithm. /// /// This is only useful for RSA keys. /// /// This corresponds to [`EVP_PKEY_CTX_set_rsa_oaep_md`]. /// /// [`EVP_PKEY_CTX_set_rsa_oaep_md`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set_rsa_oaep_md.html #[cfg(any(ossl102, libressl310))] pub fn set_rsa_oaep_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_oaep_md( self.pctx, md.as_ptr() as *mut _, )) .map(|_| ()) } } /// Sets the RSA OAEP label. /// /// This is only useful for RSA keys. /// /// This corresponds to [`EVP_PKEY_CTX_set0_rsa_oaep_label`]. /// /// [`EVP_PKEY_CTX_set0_rsa_oaep_label`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set0_rsa_oaep_label.html #[cfg(any(ossl102, libressl310))] pub fn set_rsa_oaep_label(&mut self, label: &[u8]) -> Result<(), ErrorStack> { unsafe { let p = cvt_p(ffi::CRYPTO_malloc( label.len() as _, concat!(file!(), "\0").as_ptr() as *const _, line!() as c_int, ))?; ptr::copy_nonoverlapping(label.as_ptr(), p as *mut u8, label.len()); cvt(ffi::EVP_PKEY_CTX_set0_rsa_oaep_label( self.pctx, p as *mut c_void, label.len() as c_int, )) .map(|_| ()) .map_err(|e| { #[cfg(not(ossl110))] ::ffi::CRYPTO_free(p as *mut c_void); #[cfg(ossl110)] ::ffi::CRYPTO_free( p as *mut c_void, concat!(file!(), "\0").as_ptr() as *const _, line!() as c_int, ); e }) } } /// Performs public key encryption. /// /// In order to know the size needed for the output buffer, use [`encrypt_len`](Encrypter::encrypt_len). /// Note that the length of the output buffer can be greater of the length of the encoded data. /// ``` /// # use openssl::{ /// # encrypt::Encrypter, /// # pkey::PKey, /// # rsa::{Rsa, Padding}, /// # }; /// # /// # let key = include_bytes!("../test/rsa.pem"); /// # let private_key = Rsa::private_key_from_pem(key).unwrap(); /// # let pkey = PKey::from_rsa(private_key).unwrap(); /// # let input = b"hello world".to_vec(); /// # /// let mut encrypter = Encrypter::new(&pkey).unwrap(); /// encrypter.set_rsa_padding(Padding::PKCS1).unwrap(); /// /// // Get the length of the output buffer /// let buffer_len = encrypter.encrypt_len(&input).unwrap(); /// let mut encoded = vec![0u8; buffer_len]; /// /// // Encode the data and get its length /// let encoded_len = encrypter.encrypt(&input, &mut encoded).unwrap(); /// /// // Use only the part of the buffer with the encoded data /// let encoded = &encoded[..encoded_len]; /// ``` /// /// This corresponds to [`EVP_PKEY_encrypt`]. /// /// [`EVP_PKEY_encrypt`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_encrypt.html pub fn encrypt(&self, from: &[u8], to: &mut [u8]) -> Result { let mut written = to.len(); unsafe { cvt(ffi::EVP_PKEY_encrypt( self.pctx, to.as_mut_ptr(), &mut written, from.as_ptr(), from.len(), ))?; } Ok(written) } /// Gets the size of the buffer needed to encrypt the input data. /// /// This corresponds to [`EVP_PKEY_encrypt`] called with a null pointer as output argument. /// /// [`EVP_PKEY_encrypt`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_encrypt.html pub fn encrypt_len(&self, from: &[u8]) -> Result { let mut written = 0; unsafe { cvt(ffi::EVP_PKEY_encrypt( self.pctx, ptr::null_mut(), &mut written, from.as_ptr(), from.len(), ))?; } Ok(written) } } /// A type which decrypts data. pub struct Decrypter<'a> { pctx: *mut ffi::EVP_PKEY_CTX, _p: PhantomData<&'a ()>, } unsafe impl<'a> Sync for Decrypter<'a> {} unsafe impl<'a> Send for Decrypter<'a> {} impl<'a> Drop for Decrypter<'a> { fn drop(&mut self) { unsafe { ffi::EVP_PKEY_CTX_free(self.pctx); } } } impl<'a> Decrypter<'a> { /// Creates a new `Decrypter`. /// /// OpenSSL documentation at [`EVP_PKEY_decrypt_init`]. /// /// [`EVP_PKEY_decrypt_init`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_decrypt_init.html pub fn new(pkey: &'a PKeyRef) -> Result, ErrorStack> where T: HasPrivate, { unsafe { ffi::init(); let pctx = cvt_p(ffi::EVP_PKEY_CTX_new(pkey.as_ptr(), ptr::null_mut()))?; let r = ffi::EVP_PKEY_decrypt_init(pctx); if r != 1 { ffi::EVP_PKEY_CTX_free(pctx); return Err(ErrorStack::get()); } Ok(Decrypter { pctx, _p: PhantomData, }) } } /// Returns the RSA padding mode in use. /// /// This is only useful for RSA keys. /// /// This corresponds to `EVP_PKEY_CTX_get_rsa_padding`. pub fn rsa_padding(&self) -> Result { unsafe { let mut pad = 0; cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.pctx, &mut pad)) .map(|_| Padding::from_raw(pad)) } } /// Sets the RSA padding mode. /// /// This is only useful for RSA keys. /// /// This corresponds to [`EVP_PKEY_CTX_set_rsa_padding`]. /// /// [`EVP_PKEY_CTX_set_rsa_padding`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_padding.html pub fn set_rsa_padding(&mut self, padding: Padding) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( self.pctx, padding.as_raw(), )) .map(|_| ()) } } /// Sets the RSA MGF1 algorithm. /// /// This is only useful for RSA keys. /// /// This corresponds to [`EVP_PKEY_CTX_set_rsa_mgf1_md`]. /// /// [`EVP_PKEY_CTX_set_rsa_mgf1_md`]: https://www.openssl.org/docs/manmaster/man7/RSA-PSS.html pub fn set_rsa_mgf1_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_mgf1_md( self.pctx, md.as_ptr() as *mut _, )) .map(|_| ()) } } /// Sets the RSA OAEP algorithm. /// /// This is only useful for RSA keys. /// /// This corresponds to [`EVP_PKEY_CTX_set_rsa_oaep_md`]. /// /// [`EVP_PKEY_CTX_set_rsa_oaep_md`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set_rsa_oaep_md.html #[cfg(any(ossl102, libressl310))] pub fn set_rsa_oaep_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_oaep_md( self.pctx, md.as_ptr() as *mut _, )) .map(|_| ()) } } /// Performs public key decryption. /// /// In order to know the size needed for the output buffer, use [`decrypt_len`](Decrypter::decrypt_len). /// Note that the length of the output buffer can be greater of the length of the decoded data. /// ``` /// # use openssl::{ /// # encrypt::Decrypter, /// # pkey::PKey, /// # rsa::{Rsa, Padding}, /// # }; /// # /// # const INPUT: &[u8] = b"\ /// # \x26\xa1\xc1\x13\xc5\x7f\xb4\x9f\xa0\xb4\xde\x61\x5e\x2e\xc6\xfb\x76\x5c\xd1\x2b\x5f\ /// # \x1d\x36\x60\xfa\xf8\xe8\xb3\x21\xf4\x9c\x70\xbc\x03\xea\xea\xac\xce\x4b\xb3\xf6\x45\ /// # \xcc\xb3\x80\x9e\xa8\xf7\xc3\x5d\x06\x12\x7a\xa3\x0c\x30\x67\xf1\xe7\x94\x6c\xf6\x26\ /// # \xac\x28\x17\x59\x69\xe1\xdc\xed\x7e\xc0\xe9\x62\x57\x49\xce\xdd\x13\x07\xde\x18\x03\ /// # \x0f\x9d\x61\x65\xb9\x23\x8c\x78\x4b\xad\x23\x49\x75\x47\x64\xa0\xa0\xa2\x90\xc1\x49\ /// # \x1b\x05\x24\xc2\xe9\x2c\x0d\x49\x78\x72\x61\x72\xed\x8b\x6f\x8a\xe8\xca\x05\x5c\x58\ /// # \xd6\x95\xd6\x7b\xe3\x2d\x0d\xaa\x3e\x6d\x3c\x9a\x1c\x1d\xb4\x6c\x42\x9d\x9a\x82\x55\ /// # \xd9\xde\xc8\x08\x7b\x17\xac\xd7\xaf\x86\x7b\x69\x9e\x3c\xf4\x5e\x1c\x39\x52\x6d\x62\ /// # \x50\x51\xbd\xa6\xc8\x4e\xe9\x34\xf0\x37\x0d\xa9\xa9\x77\xe6\xf5\xc2\x47\x2d\xa8\xee\ /// # \x3f\x69\x78\xff\xa9\xdc\x70\x22\x20\x9a\x5c\x9b\x70\x15\x90\xd3\xb4\x0e\x54\x9e\x48\ /// # \xed\xb6\x2c\x88\xfc\xb4\xa9\x37\x10\xfa\x71\xb2\xec\x75\xe7\xe7\x0e\xf4\x60\x2c\x7b\ /// # \x58\xaf\xa0\x53\xbd\x24\xf1\x12\xe3\x2e\x99\x25\x0a\x54\x54\x9d\xa1\xdb\xca\x41\x85\ /// # \xf4\x62\x78\x64"; /// # /// # let key = include_bytes!("../test/rsa.pem"); /// # let private_key = Rsa::private_key_from_pem(key).unwrap(); /// # let pkey = PKey::from_rsa(private_key).unwrap(); /// # let input = INPUT.to_vec(); /// # /// let mut decrypter = Decrypter::new(&pkey).unwrap(); /// decrypter.set_rsa_padding(Padding::PKCS1).unwrap(); /// /// // Get the length of the output buffer /// let buffer_len = decrypter.decrypt_len(&input).unwrap(); /// let mut decoded = vec![0u8; buffer_len]; /// /// // Decrypt the data and get its length /// let decoded_len = decrypter.decrypt(&input, &mut decoded).unwrap(); /// /// // Use only the part of the buffer with the decrypted data /// let decoded = &decoded[..decoded_len]; /// ``` /// /// This corresponds to [`EVP_PKEY_decrypt`]. /// /// [`EVP_PKEY_decrypt`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_decrypt.html pub fn decrypt(&self, from: &[u8], to: &mut [u8]) -> Result { let mut written = to.len(); unsafe { cvt(ffi::EVP_PKEY_decrypt( self.pctx, to.as_mut_ptr(), &mut written, from.as_ptr(), from.len(), ))?; } Ok(written) } /// Gets the size of the buffer needed to decrypt the input data. /// /// This corresponds to [`EVP_PKEY_decrypt`] called with a null pointer as output argument. /// /// [`EVP_PKEY_decrypt`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_decrypt.html pub fn decrypt_len(&self, from: &[u8]) -> Result { let mut written = 0; unsafe { cvt(ffi::EVP_PKEY_decrypt( self.pctx, ptr::null_mut(), &mut written, from.as_ptr(), from.len(), ))?; } Ok(written) } } #[cfg(test)] mod test { use hex::FromHex; use crate::encrypt::{Decrypter, Encrypter}; use crate::hash::MessageDigest; use crate::pkey::PKey; use crate::rsa::{Padding, Rsa}; const INPUT: &str = "65794a68624763694f694a53557a49314e694a392e65794a7063334d694f694a71623255694c41304b49434a6c\ 654841694f6a457a4d4441344d546b7a4f44417344516f67496d6830644841364c79396c654746746347786c4c\ 6d4e76625339706331397962323930496a7030636e566c6651"; #[test] fn rsa_encrypt_decrypt() { let key = include_bytes!("../test/rsa.pem"); let private_key = Rsa::private_key_from_pem(key).unwrap(); let pkey = PKey::from_rsa(private_key).unwrap(); let mut encrypter = Encrypter::new(&pkey).unwrap(); encrypter.set_rsa_padding(Padding::PKCS1).unwrap(); let input = Vec::from_hex(INPUT).unwrap(); let buffer_len = encrypter.encrypt_len(&input).unwrap(); let mut encoded = vec![0u8; buffer_len]; let encoded_len = encrypter.encrypt(&input, &mut encoded).unwrap(); let encoded = &encoded[..encoded_len]; let mut decrypter = Decrypter::new(&pkey).unwrap(); decrypter.set_rsa_padding(Padding::PKCS1).unwrap(); let buffer_len = decrypter.decrypt_len(&encoded).unwrap(); let mut decoded = vec![0u8; buffer_len]; let decoded_len = decrypter.decrypt(&encoded, &mut decoded).unwrap(); let decoded = &decoded[..decoded_len]; assert_eq!(decoded, &*input); } #[test] #[cfg(any(ossl102, libressl310))] fn rsa_encrypt_decrypt_with_sha256() { let key = include_bytes!("../test/rsa.pem"); let private_key = Rsa::private_key_from_pem(key).unwrap(); let pkey = PKey::from_rsa(private_key).unwrap(); let md = MessageDigest::sha256(); let mut encrypter = Encrypter::new(&pkey).unwrap(); encrypter.set_rsa_padding(Padding::PKCS1_OAEP).unwrap(); encrypter.set_rsa_oaep_md(md).unwrap(); encrypter.set_rsa_mgf1_md(md).unwrap(); let input = Vec::from_hex(INPUT).unwrap(); let buffer_len = encrypter.encrypt_len(&input).unwrap(); let mut encoded = vec![0u8; buffer_len]; let encoded_len = encrypter.encrypt(&input, &mut encoded).unwrap(); let encoded = &encoded[..encoded_len]; let mut decrypter = Decrypter::new(&pkey).unwrap(); decrypter.set_rsa_padding(Padding::PKCS1_OAEP).unwrap(); decrypter.set_rsa_oaep_md(md).unwrap(); decrypter.set_rsa_mgf1_md(md).unwrap(); let buffer_len = decrypter.decrypt_len(&encoded).unwrap(); let mut decoded = vec![0u8; buffer_len]; let decoded_len = decrypter.decrypt(&encoded, &mut decoded).unwrap(); let decoded = &decoded[..decoded_len]; assert_eq!(decoded, &*input); } }