From acfda134eab8049940a5fe04fba5f34a0e0dab7b Mon Sep 17 00:00:00 2001 From: Edoardo Morandi Date: Fri, 4 Dec 2020 15:15:39 +0100 Subject: [PATCH 1/8] Add encrypt module and RSA OAEP support --- openssl-sys/src/rsa.rs | 13 ++ openssl/src/encrypt.rs | 342 +++++++++++++++++++++++++++++++++++++++++ openssl/src/lib.rs | 1 + 3 files changed, 356 insertions(+) create mode 100644 openssl/src/encrypt.rs diff --git a/openssl-sys/src/rsa.rs b/openssl-sys/src/rsa.rs index 9b6ab82fbf..b1f8fe7054 100644 --- a/openssl-sys/src/rsa.rs +++ b/openssl-sys/src/rsa.rs @@ -49,6 +49,17 @@ pub unsafe fn EVP_PKEY_CTX_set_rsa_mgf1_md(ctx: *mut EVP_PKEY_CTX, md: *mut EVP_ ) } +pub unsafe fn EVP_PKEY_CTX_set_rsa_oaep_md(ctx: *mut EVP_PKEY_CTX, md: *mut EVP_MD) -> c_int { + EVP_PKEY_CTX_ctrl( + ctx, + EVP_PKEY_RSA, + EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_RSA_OAEP_MD, + 0, + md as *mut c_void, + ) +} + pub const EVP_PKEY_CTRL_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 1; pub const EVP_PKEY_CTRL_RSA_PSS_SALTLEN: c_int = EVP_PKEY_ALG_CTRL + 2; @@ -56,6 +67,8 @@ pub const EVP_PKEY_CTRL_RSA_MGF1_MD: c_int = EVP_PKEY_ALG_CTRL + 5; pub const EVP_PKEY_CTRL_GET_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 6; +pub const EVP_PKEY_CTRL_RSA_OAEP_MD: c_int = EVP_PKEY_ALG_CTRL + 9; + pub const RSA_PKCS1_PADDING: c_int = 1; pub const RSA_SSLV23_PADDING: c_int = 2; pub const RSA_NO_PADDING: c_int = 3; diff --git a/openssl/src/encrypt.rs b/openssl/src/encrypt.rs new file mode 100644 index 0000000000..909bf6bd76 --- /dev/null +++ b/openssl/src/encrypt.rs @@ -0,0 +1,342 @@ +use std::{marker::PhantomData, ptr}; + +use error::ErrorStack; +use foreign_types::ForeignTypeRef; +use hash::MessageDigest; +use pkey::{HasPrivate, HasPublic, PKeyRef}; +use rsa::Padding; +use {cvt, cvt_p}; + +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, + { + Self::new_intern(pkey) + } + + fn new_intern(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 + 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 encryption. + /// + /// 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) + } +} +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, + { + Self::new_intern(pkey) + } + + fn new_intern(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 + 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. + /// + /// 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) + } +} + +#[cfg(test)] +mod test { + use hex::FromHex; + + use encrypt::{Decrypter, Encrypter}; + use hash::MessageDigest; + use pkey::PKey; + use 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 mut encoded = vec![0u8; INPUT.len() * 3]; + 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 mut decoded = vec![0u8; encoded.len()]; + let decoded_len = decrypter.decrypt(&encoded, &mut decoded).unwrap(); + let decoded = &decoded[..decoded_len]; + + assert_eq!(decoded, input); + } + + #[test] + 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 mut encoded = vec![0u8; INPUT.len() * 3]; + 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 mut decoded = vec![0u8; encoded.len()]; + let decoded_len = decrypter.decrypt(&encoded, &mut decoded).unwrap(); + let decoded = &decoded[..decoded_len]; + + assert_eq!(decoded, input); + } +} diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index b4e647c076..5389ed5968 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -151,6 +151,7 @@ pub mod dh; pub mod dsa; pub mod ec; pub mod ecdsa; +pub mod encrypt; pub mod envelope; pub mod error; pub mod ex_data; From 243d9f94e6b4eba1fb890b22d505d3023003570b Mon Sep 17 00:00:00 2001 From: Edoardo Morandi Date: Fri, 4 Dec 2020 15:55:55 +0100 Subject: [PATCH 2/8] Fix compilation with old compiler --- openssl/src/encrypt.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openssl/src/encrypt.rs b/openssl/src/encrypt.rs index 909bf6bd76..9d524690c5 100644 --- a/openssl/src/encrypt.rs +++ b/openssl/src/encrypt.rs @@ -309,7 +309,7 @@ mod test { let decoded_len = decrypter.decrypt(&encoded, &mut decoded).unwrap(); let decoded = &decoded[..decoded_len]; - assert_eq!(decoded, input); + assert_eq!(decoded, &*input); } #[test] @@ -337,6 +337,6 @@ mod test { let decoded_len = decrypter.decrypt(&encoded, &mut decoded).unwrap(); let decoded = &decoded[..decoded_len]; - assert_eq!(decoded, input); + assert_eq!(decoded, &*input); } } From 411ad0f06653be32110e0d94e41418452df0e3dd Mon Sep 17 00:00:00 2001 From: Edoardo Morandi Date: Sat, 5 Dec 2020 13:28:00 +0100 Subject: [PATCH 3/8] Remove unnecessary new_intern --- openssl/src/encrypt.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/openssl/src/encrypt.rs b/openssl/src/encrypt.rs index 9d524690c5..aec2270839 100644 --- a/openssl/src/encrypt.rs +++ b/openssl/src/encrypt.rs @@ -30,13 +30,6 @@ impl<'a> Encrypter<'a> { /// /// [`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, - { - Self::new_intern(pkey) - } - - fn new_intern(pkey: &'a PKeyRef) -> Result, ErrorStack> where T: HasPublic, { @@ -164,13 +157,6 @@ impl<'a> Decrypter<'a> { /// /// [`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, - { - Self::new_intern(pkey) - } - - fn new_intern(pkey: &'a PKeyRef) -> Result, ErrorStack> where T: HasPrivate, { From b2410923fe57b41dd4e1cdfb7894aaf326d5f936 Mon Sep 17 00:00:00 2001 From: Edoardo Morandi Date: Sat, 5 Dec 2020 15:31:29 +0100 Subject: [PATCH 4/8] Add minimal openssl/libressl version for OAEP --- openssl-sys/src/rsa.rs | 2 ++ openssl/src/encrypt.rs | 3 +++ 2 files changed, 5 insertions(+) diff --git a/openssl-sys/src/rsa.rs b/openssl-sys/src/rsa.rs index b1f8fe7054..dd7cab959b 100644 --- a/openssl-sys/src/rsa.rs +++ b/openssl-sys/src/rsa.rs @@ -49,6 +49,7 @@ pub unsafe fn EVP_PKEY_CTX_set_rsa_mgf1_md(ctx: *mut EVP_PKEY_CTX, md: *mut EVP_ ) } +#[cfg(any(ossl102, libressl310))] pub unsafe fn EVP_PKEY_CTX_set_rsa_oaep_md(ctx: *mut EVP_PKEY_CTX, md: *mut EVP_MD) -> c_int { EVP_PKEY_CTX_ctrl( ctx, @@ -67,6 +68,7 @@ pub const EVP_PKEY_CTRL_RSA_MGF1_MD: c_int = EVP_PKEY_ALG_CTRL + 5; pub const EVP_PKEY_CTRL_GET_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 6; +#[cfg(any(ossl102, libressl310))] pub const EVP_PKEY_CTRL_RSA_OAEP_MD: c_int = EVP_PKEY_ALG_CTRL + 9; pub const RSA_PKCS1_PADDING: c_int = 1; diff --git a/openssl/src/encrypt.rs b/openssl/src/encrypt.rs index aec2270839..37fc690ce3 100644 --- a/openssl/src/encrypt.rs +++ b/openssl/src/encrypt.rs @@ -104,6 +104,7 @@ impl<'a> Encrypter<'a> { /// 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( @@ -231,6 +232,7 @@ impl<'a> Decrypter<'a> { /// 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( @@ -299,6 +301,7 @@ mod test { } #[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(); From d0676bf38d773989d60b342a9efc960c30a4b1fd Mon Sep 17 00:00:00 2001 From: Edoardo Morandi Date: Sat, 5 Dec 2020 18:20:28 +0100 Subject: [PATCH 5/8] Add encrypt_len and decrypt_len --- openssl/src/encrypt.rs | 44 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/openssl/src/encrypt.rs b/openssl/src/encrypt.rs index 37fc690ce3..24d35a853a 100644 --- a/openssl/src/encrypt.rs +++ b/openssl/src/encrypt.rs @@ -117,6 +117,8 @@ impl<'a> Encrypter<'a> { /// Performs public key encryption. /// + /// In order to know the size needed for the output buffer, use [`encrypt_len`](Encrypter::encrypt_len). + /// /// This corresponds to [`EVP_PKEY_encrypt`]. /// /// [`EVP_PKEY_encrypt`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_encrypt.html @@ -134,6 +136,26 @@ impl<'a> Encrypter<'a> { 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) + } } pub struct Decrypter<'a> { pctx: *mut ffi::EVP_PKEY_CTX, @@ -245,6 +267,8 @@ impl<'a> Decrypter<'a> { /// Performs public key decryption. /// + /// In order to know the size needed for the output buffer, use [`decrypt_len`](Decrypter::decrypt_len). + /// /// This corresponds to [`EVP_PKEY_decrypt`]. /// /// [`EVP_PKEY_decrypt`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_decrypt.html @@ -262,6 +286,26 @@ impl<'a> Decrypter<'a> { 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)] From 03d8720ac6e1da662b486350a46a4f99e5a0505f Mon Sep 17 00:00:00 2001 From: Edoardo Morandi Date: Sat, 5 Dec 2020 18:26:56 +0100 Subject: [PATCH 6/8] Make the tests use `encrypt_len`/`decrypt_len` --- openssl/src/encrypt.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/openssl/src/encrypt.rs b/openssl/src/encrypt.rs index 24d35a853a..3eaae1ae26 100644 --- a/openssl/src/encrypt.rs +++ b/openssl/src/encrypt.rs @@ -331,13 +331,15 @@ mod test { let mut encrypter = Encrypter::new(&pkey).unwrap(); encrypter.set_rsa_padding(Padding::PKCS1).unwrap(); let input = Vec::from_hex(INPUT).unwrap(); - let mut encoded = vec![0u8; INPUT.len() * 3]; + 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 mut decoded = vec![0u8; encoded.len()]; + 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]; @@ -358,7 +360,8 @@ mod test { encrypter.set_rsa_oaep_md(md).unwrap(); encrypter.set_rsa_mgf1_md(md).unwrap(); let input = Vec::from_hex(INPUT).unwrap(); - let mut encoded = vec![0u8; INPUT.len() * 3]; + 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]; @@ -366,7 +369,8 @@ mod test { decrypter.set_rsa_padding(Padding::PKCS1_OAEP).unwrap(); decrypter.set_rsa_oaep_md(md).unwrap(); decrypter.set_rsa_mgf1_md(md).unwrap(); - let mut decoded = vec![0u8; encoded.len()]; + 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]; From 76d935ec024185d3477a875dc392df2f06efc50b Mon Sep 17 00:00:00 2001 From: Edoardo Morandi Date: Sat, 5 Dec 2020 18:54:36 +0100 Subject: [PATCH 7/8] Improve documentation for `encrypt` and `decrypt` --- openssl/src/encrypt.rs | 67 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/openssl/src/encrypt.rs b/openssl/src/encrypt.rs index 3eaae1ae26..042917ddf2 100644 --- a/openssl/src/encrypt.rs +++ b/openssl/src/encrypt.rs @@ -118,6 +118,32 @@ impl<'a> Encrypter<'a> { /// 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`]. /// @@ -268,6 +294,47 @@ impl<'a> Decrypter<'a> { /// 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`]. /// From c4b3f591054b34b7a63945d0682e8767ecfbc83d Mon Sep 17 00:00:00 2001 From: Edoardo Morandi Date: Mon, 7 Dec 2020 09:52:15 +0100 Subject: [PATCH 8/8] Add some module and types documentation --- openssl/src/encrypt.rs | 44 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/openssl/src/encrypt.rs b/openssl/src/encrypt.rs index 042917ddf2..0d28ac9edc 100644 --- a/openssl/src/encrypt.rs +++ b/openssl/src/encrypt.rs @@ -1,3 +1,44 @@ +//! 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 std::{marker::PhantomData, ptr}; use error::ErrorStack; @@ -7,6 +48,7 @@ use pkey::{HasPrivate, HasPublic, PKeyRef}; use rsa::Padding; use {cvt, cvt_p}; +/// A type which encrypts data. pub struct Encrypter<'a> { pctx: *mut ffi::EVP_PKEY_CTX, _p: PhantomData<&'a ()>, @@ -183,6 +225,8 @@ impl<'a> Encrypter<'a> { Ok(written) } } + +/// A type which decrypts data. pub struct Decrypter<'a> { pctx: *mut ffi::EVP_PKEY_CTX, _p: PhantomData<&'a ()>,