summaryrefslogtreecommitdiffstats
path: root/vendor/openssl/src/rsa.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/openssl/src/rsa.rs')
-rw-r--r--vendor/openssl/src/rsa.rs852
1 files changed, 852 insertions, 0 deletions
diff --git a/vendor/openssl/src/rsa.rs b/vendor/openssl/src/rsa.rs
new file mode 100644
index 000000000..68cf64b03
--- /dev/null
+++ b/vendor/openssl/src/rsa.rs
@@ -0,0 +1,852 @@
+//! Rivest–Shamir–Adleman cryptosystem
+//!
+//! RSA is one of the earliest asymmetric public key encryption schemes.
+//! Like many other cryptosystems, RSA relies on the presumed difficulty of a hard
+//! mathematical problem, namely factorization of the product of two large prime
+//! numbers. At the moment there does not exist an algorithm that can factor such
+//! large numbers in reasonable time. RSA is used in a wide variety of
+//! applications including digital signatures and key exchanges such as
+//! establishing a TLS/SSL connection.
+//!
+//! The RSA acronym is derived from the first letters of the surnames of the
+//! algorithm's founding trio.
+//!
+//! # Example
+//!
+//! Generate a 2048-bit RSA key pair and use the public key to encrypt some data.
+//!
+//! ```rust
+//! use openssl::rsa::{Rsa, Padding};
+//!
+//! let rsa = Rsa::generate(2048).unwrap();
+//! let data = b"foobar";
+//! let mut buf = vec![0; rsa.size() as usize];
+//! let encrypted_len = rsa.public_encrypt(data, &mut buf, Padding::PKCS1).unwrap();
+//! ```
+use cfg_if::cfg_if;
+use foreign_types::{ForeignType, ForeignTypeRef};
+use libc::c_int;
+use std::fmt;
+use std::mem;
+use std::ptr;
+
+use crate::bn::{BigNum, BigNumRef};
+use crate::error::ErrorStack;
+use crate::pkey::{HasPrivate, HasPublic, Private, Public};
+use crate::util::ForeignTypeRefExt;
+use crate::{cvt, cvt_n, cvt_p, LenType};
+use openssl_macros::corresponds;
+
+/// Type of encryption padding to use.
+///
+/// Random length padding is primarily used to prevent attackers from
+/// predicting or knowing the exact length of a plaintext message that
+/// can possibly lead to breaking encryption.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct Padding(c_int);
+
+impl Padding {
+ pub const NONE: Padding = Padding(ffi::RSA_NO_PADDING);
+ pub const PKCS1: Padding = Padding(ffi::RSA_PKCS1_PADDING);
+ pub const PKCS1_OAEP: Padding = Padding(ffi::RSA_PKCS1_OAEP_PADDING);
+ pub const PKCS1_PSS: Padding = Padding(ffi::RSA_PKCS1_PSS_PADDING);
+
+ /// Creates a `Padding` from an integer representation.
+ pub fn from_raw(value: c_int) -> Padding {
+ Padding(value)
+ }
+
+ /// Returns the integer representation of `Padding`.
+ #[allow(clippy::trivially_copy_pass_by_ref)]
+ pub fn as_raw(&self) -> c_int {
+ self.0
+ }
+}
+
+generic_foreign_type_and_impl_send_sync! {
+ type CType = ffi::RSA;
+ fn drop = ffi::RSA_free;
+
+ /// An RSA key.
+ pub struct Rsa<T>;
+
+ /// Reference to `RSA`
+ pub struct RsaRef<T>;
+}
+
+impl<T> Clone for Rsa<T> {
+ fn clone(&self) -> Rsa<T> {
+ (**self).to_owned()
+ }
+}
+
+impl<T> ToOwned for RsaRef<T> {
+ type Owned = Rsa<T>;
+
+ fn to_owned(&self) -> Rsa<T> {
+ unsafe {
+ ffi::RSA_up_ref(self.as_ptr());
+ Rsa::from_ptr(self.as_ptr())
+ }
+ }
+}
+
+impl<T> RsaRef<T>
+where
+ T: HasPrivate,
+{
+ private_key_to_pem! {
+ /// Serializes the private key to a PEM-encoded PKCS#1 RSAPrivateKey structure.
+ ///
+ /// The output will have a header of `-----BEGIN RSA PRIVATE KEY-----`.
+ #[corresponds(PEM_write_bio_RSAPrivateKey)]
+ private_key_to_pem,
+ /// Serializes the private key to a PEM-encoded encrypted PKCS#1 RSAPrivateKey structure.
+ ///
+ /// The output will have a header of `-----BEGIN RSA PRIVATE KEY-----`.
+ #[corresponds(PEM_write_bio_RSAPrivateKey)]
+ private_key_to_pem_passphrase,
+ ffi::PEM_write_bio_RSAPrivateKey
+ }
+
+ to_der! {
+ /// Serializes the private key to a DER-encoded PKCS#1 RSAPrivateKey structure.
+ #[corresponds(i2d_RSAPrivateKey)]
+ private_key_to_der,
+ ffi::i2d_RSAPrivateKey
+ }
+
+ /// Decrypts data using the private key, returning the number of decrypted bytes.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `self` has no private components, or if `to` is smaller
+ /// than `self.size()`.
+ #[corresponds(RSA_private_decrypt)]
+ pub fn private_decrypt(
+ &self,
+ from: &[u8],
+ to: &mut [u8],
+ padding: Padding,
+ ) -> Result<usize, ErrorStack> {
+ assert!(from.len() <= i32::max_value() as usize);
+ assert!(to.len() >= self.size() as usize);
+
+ unsafe {
+ let len = cvt_n(ffi::RSA_private_decrypt(
+ from.len() as LenType,
+ from.as_ptr(),
+ to.as_mut_ptr(),
+ self.as_ptr(),
+ padding.0,
+ ))?;
+ Ok(len as usize)
+ }
+ }
+
+ /// Encrypts data using the private key, returning the number of encrypted bytes.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `self` has no private components, or if `to` is smaller
+ /// than `self.size()`.
+ #[corresponds(RSA_private_encrypt)]
+ pub fn private_encrypt(
+ &self,
+ from: &[u8],
+ to: &mut [u8],
+ padding: Padding,
+ ) -> Result<usize, ErrorStack> {
+ assert!(from.len() <= i32::max_value() as usize);
+ assert!(to.len() >= self.size() as usize);
+
+ unsafe {
+ let len = cvt_n(ffi::RSA_private_encrypt(
+ from.len() as LenType,
+ from.as_ptr(),
+ to.as_mut_ptr(),
+ self.as_ptr(),
+ padding.0,
+ ))?;
+ Ok(len as usize)
+ }
+ }
+
+ /// Returns a reference to the private exponent of the key.
+ #[corresponds(RSA_get0_key)]
+ pub fn d(&self) -> &BigNumRef {
+ unsafe {
+ let mut d = ptr::null();
+ RSA_get0_key(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut d);
+ BigNumRef::from_const_ptr(d)
+ }
+ }
+
+ /// Returns a reference to the first factor of the exponent of the key.
+ #[corresponds(RSA_get0_factors)]
+ pub fn p(&self) -> Option<&BigNumRef> {
+ unsafe {
+ let mut p = ptr::null();
+ RSA_get0_factors(self.as_ptr(), &mut p, ptr::null_mut());
+ BigNumRef::from_const_ptr_opt(p)
+ }
+ }
+
+ /// Returns a reference to the second factor of the exponent of the key.
+ #[corresponds(RSA_get0_factors)]
+ pub fn q(&self) -> Option<&BigNumRef> {
+ unsafe {
+ let mut q = ptr::null();
+ RSA_get0_factors(self.as_ptr(), ptr::null_mut(), &mut q);
+ BigNumRef::from_const_ptr_opt(q)
+ }
+ }
+
+ /// Returns a reference to the first exponent used for CRT calculations.
+ #[corresponds(RSA_get0_crt_params)]
+ pub fn dmp1(&self) -> Option<&BigNumRef> {
+ unsafe {
+ let mut dp = ptr::null();
+ RSA_get0_crt_params(self.as_ptr(), &mut dp, ptr::null_mut(), ptr::null_mut());
+ BigNumRef::from_const_ptr_opt(dp)
+ }
+ }
+
+ /// Returns a reference to the second exponent used for CRT calculations.
+ #[corresponds(RSA_get0_crt_params)]
+ pub fn dmq1(&self) -> Option<&BigNumRef> {
+ unsafe {
+ let mut dq = ptr::null();
+ RSA_get0_crt_params(self.as_ptr(), ptr::null_mut(), &mut dq, ptr::null_mut());
+ BigNumRef::from_const_ptr_opt(dq)
+ }
+ }
+
+ /// Returns a reference to the coefficient used for CRT calculations.
+ #[corresponds(RSA_get0_crt_params)]
+ pub fn iqmp(&self) -> Option<&BigNumRef> {
+ unsafe {
+ let mut qi = ptr::null();
+ RSA_get0_crt_params(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut qi);
+ BigNumRef::from_const_ptr_opt(qi)
+ }
+ }
+
+ /// Validates RSA parameters for correctness
+ #[corresponds(RSA_check_key)]
+ #[allow(clippy::unnecessary_cast)]
+ pub fn check_key(&self) -> Result<bool, ErrorStack> {
+ unsafe {
+ let result = ffi::RSA_check_key(self.as_ptr()) as i32;
+ if result == -1 {
+ Err(ErrorStack::get())
+ } else {
+ Ok(result == 1)
+ }
+ }
+ }
+}
+
+impl<T> RsaRef<T>
+where
+ T: HasPublic,
+{
+ to_pem! {
+ /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure.
+ ///
+ /// The output will have a header of `-----BEGIN PUBLIC KEY-----`.
+ #[corresponds(PEM_write_bio_RSA_PUBKEY)]
+ public_key_to_pem,
+ ffi::PEM_write_bio_RSA_PUBKEY
+ }
+
+ to_der! {
+ /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure.
+ #[corresponds(i2d_RSA_PUBKEY)]
+ public_key_to_der,
+ ffi::i2d_RSA_PUBKEY
+ }
+
+ to_pem! {
+ /// Serializes the public key into a PEM-encoded PKCS#1 RSAPublicKey structure.
+ ///
+ /// The output will have a header of `-----BEGIN RSA PUBLIC KEY-----`.
+ #[corresponds(PEM_write_bio_RSAPublicKey)]
+ public_key_to_pem_pkcs1,
+ ffi::PEM_write_bio_RSAPublicKey
+ }
+
+ to_der! {
+ /// Serializes the public key into a DER-encoded PKCS#1 RSAPublicKey structure.
+ #[corresponds(i2d_RSAPublicKey)]
+ public_key_to_der_pkcs1,
+ ffi::i2d_RSAPublicKey
+ }
+
+ /// Returns the size of the modulus in bytes.
+ #[corresponds(RSA_size)]
+ pub fn size(&self) -> u32 {
+ unsafe { ffi::RSA_size(self.as_ptr()) as u32 }
+ }
+
+ /// Decrypts data using the public key, returning the number of decrypted bytes.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `to` is smaller than `self.size()`.
+ #[corresponds(RSA_public_decrypt)]
+ pub fn public_decrypt(
+ &self,
+ from: &[u8],
+ to: &mut [u8],
+ padding: Padding,
+ ) -> Result<usize, ErrorStack> {
+ assert!(from.len() <= i32::max_value() as usize);
+ assert!(to.len() >= self.size() as usize);
+
+ unsafe {
+ let len = cvt_n(ffi::RSA_public_decrypt(
+ from.len() as LenType,
+ from.as_ptr(),
+ to.as_mut_ptr(),
+ self.as_ptr(),
+ padding.0,
+ ))?;
+ Ok(len as usize)
+ }
+ }
+
+ /// Encrypts data using the public key, returning the number of encrypted bytes.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `to` is smaller than `self.size()`.
+ #[corresponds(RSA_public_encrypt)]
+ pub fn public_encrypt(
+ &self,
+ from: &[u8],
+ to: &mut [u8],
+ padding: Padding,
+ ) -> Result<usize, ErrorStack> {
+ assert!(from.len() <= i32::max_value() as usize);
+ assert!(to.len() >= self.size() as usize);
+
+ unsafe {
+ let len = cvt_n(ffi::RSA_public_encrypt(
+ from.len() as LenType,
+ from.as_ptr(),
+ to.as_mut_ptr(),
+ self.as_ptr(),
+ padding.0,
+ ))?;
+ Ok(len as usize)
+ }
+ }
+
+ /// Returns a reference to the modulus of the key.
+ #[corresponds(RSA_get0_key)]
+ pub fn n(&self) -> &BigNumRef {
+ unsafe {
+ let mut n = ptr::null();
+ RSA_get0_key(self.as_ptr(), &mut n, ptr::null_mut(), ptr::null_mut());
+ BigNumRef::from_const_ptr(n)
+ }
+ }
+
+ /// Returns a reference to the public exponent of the key.
+ #[corresponds(RSA_get0_key)]
+ pub fn e(&self) -> &BigNumRef {
+ unsafe {
+ let mut e = ptr::null();
+ RSA_get0_key(self.as_ptr(), ptr::null_mut(), &mut e, ptr::null_mut());
+ BigNumRef::from_const_ptr(e)
+ }
+ }
+}
+
+impl Rsa<Public> {
+ /// Creates a new RSA key with only public components.
+ ///
+ /// `n` is the modulus common to both public and private key.
+ /// `e` is the public exponent.
+ ///
+ /// This corresponds to [`RSA_new`] and uses [`RSA_set0_key`].
+ ///
+ /// [`RSA_new`]: https://www.openssl.org/docs/manmaster/crypto/RSA_new.html
+ /// [`RSA_set0_key`]: https://www.openssl.org/docs/manmaster/crypto/RSA_set0_key.html
+ pub fn from_public_components(n: BigNum, e: BigNum) -> Result<Rsa<Public>, ErrorStack> {
+ unsafe {
+ let rsa = cvt_p(ffi::RSA_new())?;
+ RSA_set0_key(rsa, n.as_ptr(), e.as_ptr(), ptr::null_mut());
+ mem::forget((n, e));
+ Ok(Rsa::from_ptr(rsa))
+ }
+ }
+
+ from_pem! {
+ /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing an RSA key.
+ ///
+ /// The input should have a header of `-----BEGIN PUBLIC KEY-----`.
+ #[corresponds(PEM_read_bio_RSA_PUBKEY)]
+ public_key_from_pem,
+ Rsa<Public>,
+ ffi::PEM_read_bio_RSA_PUBKEY
+ }
+
+ from_pem! {
+ /// Decodes a PEM-encoded PKCS#1 RSAPublicKey structure.
+ ///
+ /// The input should have a header of `-----BEGIN RSA PUBLIC KEY-----`.
+ #[corresponds(PEM_read_bio_RSAPublicKey)]
+ public_key_from_pem_pkcs1,
+ Rsa<Public>,
+ ffi::PEM_read_bio_RSAPublicKey
+ }
+
+ from_der! {
+ /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing an RSA key.
+ #[corresponds(d2i_RSA_PUBKEY)]
+ public_key_from_der,
+ Rsa<Public>,
+ ffi::d2i_RSA_PUBKEY
+ }
+
+ from_der! {
+ /// Decodes a DER-encoded PKCS#1 RSAPublicKey structure.
+ #[corresponds(d2i_RSAPublicKey)]
+ public_key_from_der_pkcs1,
+ Rsa<Public>,
+ ffi::d2i_RSAPublicKey
+ }
+}
+
+pub struct RsaPrivateKeyBuilder {
+ rsa: Rsa<Private>,
+}
+
+impl RsaPrivateKeyBuilder {
+ /// Creates a new `RsaPrivateKeyBuilder`.
+ ///
+ /// `n` is the modulus common to both public and private key.
+ /// `e` is the public exponent and `d` is the private exponent.
+ ///
+ /// This corresponds to [`RSA_new`] and uses [`RSA_set0_key`].
+ ///
+ /// [`RSA_new`]: https://www.openssl.org/docs/manmaster/crypto/RSA_new.html
+ /// [`RSA_set0_key`]: https://www.openssl.org/docs/manmaster/crypto/RSA_set0_key.html
+ pub fn new(n: BigNum, e: BigNum, d: BigNum) -> Result<RsaPrivateKeyBuilder, ErrorStack> {
+ unsafe {
+ let rsa = cvt_p(ffi::RSA_new())?;
+ RSA_set0_key(rsa, n.as_ptr(), e.as_ptr(), d.as_ptr());
+ mem::forget((n, e, d));
+ Ok(RsaPrivateKeyBuilder {
+ rsa: Rsa::from_ptr(rsa),
+ })
+ }
+ }
+
+ /// Sets the factors of the Rsa key.
+ ///
+ /// `p` and `q` are the first and second factors of `n`.
+ #[corresponds(RSA_set0_factors)]
+ // FIXME should be infallible
+ pub fn set_factors(self, p: BigNum, q: BigNum) -> Result<RsaPrivateKeyBuilder, ErrorStack> {
+ unsafe {
+ RSA_set0_factors(self.rsa.as_ptr(), p.as_ptr(), q.as_ptr());
+ mem::forget((p, q));
+ }
+ Ok(self)
+ }
+
+ /// Sets the Chinese Remainder Theorem params of the Rsa key.
+ ///
+ /// `dmp1`, `dmq1`, and `iqmp` are the exponents and coefficient for
+ /// CRT calculations which is used to speed up RSA operations.
+ #[corresponds(RSA_set0_crt_params)]
+ // FIXME should be infallible
+ pub fn set_crt_params(
+ self,
+ dmp1: BigNum,
+ dmq1: BigNum,
+ iqmp: BigNum,
+ ) -> Result<RsaPrivateKeyBuilder, ErrorStack> {
+ unsafe {
+ RSA_set0_crt_params(
+ self.rsa.as_ptr(),
+ dmp1.as_ptr(),
+ dmq1.as_ptr(),
+ iqmp.as_ptr(),
+ );
+ mem::forget((dmp1, dmq1, iqmp));
+ }
+ Ok(self)
+ }
+
+ /// Returns the Rsa key.
+ pub fn build(self) -> Rsa<Private> {
+ self.rsa
+ }
+}
+
+impl Rsa<Private> {
+ /// Creates a new RSA key with private components (public components are assumed).
+ ///
+ /// This a convenience method over:
+ /// ```
+ /// # use openssl::rsa::RsaPrivateKeyBuilder;
+ /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
+ /// # let bn = || openssl::bn::BigNum::new().unwrap();
+ /// # let (n, e, d, p, q, dmp1, dmq1, iqmp) = (bn(), bn(), bn(), bn(), bn(), bn(), bn(), bn());
+ /// RsaPrivateKeyBuilder::new(n, e, d)?
+ /// .set_factors(p, q)?
+ /// .set_crt_params(dmp1, dmq1, iqmp)?
+ /// .build();
+ /// # Ok(()) }
+ /// ```
+ #[allow(clippy::too_many_arguments, clippy::many_single_char_names)]
+ pub fn from_private_components(
+ n: BigNum,
+ e: BigNum,
+ d: BigNum,
+ p: BigNum,
+ q: BigNum,
+ dmp1: BigNum,
+ dmq1: BigNum,
+ iqmp: BigNum,
+ ) -> Result<Rsa<Private>, ErrorStack> {
+ Ok(RsaPrivateKeyBuilder::new(n, e, d)?
+ .set_factors(p, q)?
+ .set_crt_params(dmp1, dmq1, iqmp)?
+ .build())
+ }
+
+ /// Generates a public/private key pair with the specified size.
+ ///
+ /// The public exponent will be 65537.
+ #[corresponds(RSA_generate_key_ex)]
+ pub fn generate(bits: u32) -> Result<Rsa<Private>, ErrorStack> {
+ let e = BigNum::from_u32(ffi::RSA_F4 as u32)?;
+ Rsa::generate_with_e(bits, &e)
+ }
+
+ /// Generates a public/private key pair with the specified size and a custom exponent.
+ ///
+ /// Unless you have specific needs and know what you're doing, use `Rsa::generate` instead.
+ #[corresponds(RSA_generate_key_ex)]
+ pub fn generate_with_e(bits: u32, e: &BigNumRef) -> Result<Rsa<Private>, ErrorStack> {
+ unsafe {
+ let rsa = Rsa::from_ptr(cvt_p(ffi::RSA_new())?);
+ cvt(ffi::RSA_generate_key_ex(
+ rsa.0,
+ bits as c_int,
+ e.as_ptr(),
+ ptr::null_mut(),
+ ))?;
+ Ok(rsa)
+ }
+ }
+
+ // FIXME these need to identify input formats
+ private_key_from_pem! {
+ /// Deserializes a private key from a PEM-encoded PKCS#1 RSAPrivateKey structure.
+ #[corresponds(PEM_read_bio_RSAPrivateKey)]
+ private_key_from_pem,
+
+ /// Deserializes a private key from a PEM-encoded encrypted PKCS#1 RSAPrivateKey structure.
+ #[corresponds(PEM_read_bio_RSAPrivateKey)]
+ private_key_from_pem_passphrase,
+
+ /// Deserializes a private key from a PEM-encoded encrypted PKCS#1 RSAPrivateKey structure.
+ ///
+ /// The callback should fill the password into the provided buffer and return its length.
+ #[corresponds(PEM_read_bio_RSAPrivateKey)]
+ private_key_from_pem_callback,
+ Rsa<Private>,
+ ffi::PEM_read_bio_RSAPrivateKey
+ }
+
+ from_der! {
+ /// Decodes a DER-encoded PKCS#1 RSAPrivateKey structure.
+ #[corresponds(d2i_RSAPrivateKey)]
+ private_key_from_der,
+ Rsa<Private>,
+ ffi::d2i_RSAPrivateKey
+ }
+}
+
+impl<T> fmt::Debug for Rsa<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Rsa")
+ }
+}
+
+cfg_if! {
+ if #[cfg(any(ossl110, libressl273))] {
+ use ffi::{
+ RSA_get0_key, RSA_get0_factors, RSA_get0_crt_params, RSA_set0_key, RSA_set0_factors,
+ RSA_set0_crt_params,
+ };
+ } else {
+ #[allow(bad_style)]
+ unsafe fn RSA_get0_key(
+ r: *const ffi::RSA,
+ n: *mut *const ffi::BIGNUM,
+ e: *mut *const ffi::BIGNUM,
+ d: *mut *const ffi::BIGNUM,
+ ) {
+ if !n.is_null() {
+ *n = (*r).n;
+ }
+ if !e.is_null() {
+ *e = (*r).e;
+ }
+ if !d.is_null() {
+ *d = (*r).d;
+ }
+ }
+
+ #[allow(bad_style)]
+ unsafe fn RSA_get0_factors(
+ r: *const ffi::RSA,
+ p: *mut *const ffi::BIGNUM,
+ q: *mut *const ffi::BIGNUM,
+ ) {
+ if !p.is_null() {
+ *p = (*r).p;
+ }
+ if !q.is_null() {
+ *q = (*r).q;
+ }
+ }
+
+ #[allow(bad_style)]
+ unsafe fn RSA_get0_crt_params(
+ r: *const ffi::RSA,
+ dmp1: *mut *const ffi::BIGNUM,
+ dmq1: *mut *const ffi::BIGNUM,
+ iqmp: *mut *const ffi::BIGNUM,
+ ) {
+ if !dmp1.is_null() {
+ *dmp1 = (*r).dmp1;
+ }
+ if !dmq1.is_null() {
+ *dmq1 = (*r).dmq1;
+ }
+ if !iqmp.is_null() {
+ *iqmp = (*r).iqmp;
+ }
+ }
+
+ #[allow(bad_style)]
+ unsafe fn RSA_set0_key(
+ r: *mut ffi::RSA,
+ n: *mut ffi::BIGNUM,
+ e: *mut ffi::BIGNUM,
+ d: *mut ffi::BIGNUM,
+ ) -> c_int {
+ (*r).n = n;
+ (*r).e = e;
+ (*r).d = d;
+ 1
+ }
+
+ #[allow(bad_style)]
+ unsafe fn RSA_set0_factors(
+ r: *mut ffi::RSA,
+ p: *mut ffi::BIGNUM,
+ q: *mut ffi::BIGNUM,
+ ) -> c_int {
+ (*r).p = p;
+ (*r).q = q;
+ 1
+ }
+
+ #[allow(bad_style)]
+ unsafe fn RSA_set0_crt_params(
+ r: *mut ffi::RSA,
+ dmp1: *mut ffi::BIGNUM,
+ dmq1: *mut ffi::BIGNUM,
+ iqmp: *mut ffi::BIGNUM,
+ ) -> c_int {
+ (*r).dmp1 = dmp1;
+ (*r).dmq1 = dmq1;
+ (*r).iqmp = iqmp;
+ 1
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use crate::symm::Cipher;
+
+ use super::*;
+
+ #[test]
+ fn test_from_password() {
+ let key = include_bytes!("../test/rsa-encrypted.pem");
+ Rsa::private_key_from_pem_passphrase(key, b"mypass").unwrap();
+ }
+
+ #[test]
+ fn test_from_password_callback() {
+ let mut password_queried = false;
+ let key = include_bytes!("../test/rsa-encrypted.pem");
+ Rsa::private_key_from_pem_callback(key, |password| {
+ password_queried = true;
+ password[..6].copy_from_slice(b"mypass");
+ Ok(6)
+ })
+ .unwrap();
+
+ assert!(password_queried);
+ }
+
+ #[test]
+ fn test_to_password() {
+ let key = Rsa::generate(2048).unwrap();
+ let pem = key
+ .private_key_to_pem_passphrase(Cipher::aes_128_cbc(), b"foobar")
+ .unwrap();
+ Rsa::private_key_from_pem_passphrase(&pem, b"foobar").unwrap();
+ assert!(Rsa::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err());
+ }
+
+ #[test]
+ fn test_public_encrypt_private_decrypt_with_padding() {
+ let key = include_bytes!("../test/rsa.pem.pub");
+ let public_key = Rsa::public_key_from_pem(key).unwrap();
+
+ let mut result = vec![0; public_key.size() as usize];
+ let original_data = b"This is test";
+ let len = public_key
+ .public_encrypt(original_data, &mut result, Padding::PKCS1)
+ .unwrap();
+ assert_eq!(len, 256);
+
+ let pkey = include_bytes!("../test/rsa.pem");
+ let private_key = Rsa::private_key_from_pem(pkey).unwrap();
+ let mut dec_result = vec![0; private_key.size() as usize];
+ let len = private_key
+ .private_decrypt(&result, &mut dec_result, Padding::PKCS1)
+ .unwrap();
+
+ assert_eq!(&dec_result[..len], original_data);
+ }
+
+ #[test]
+ fn test_private_encrypt() {
+ let k0 = super::Rsa::generate(512).unwrap();
+ let k0pkey = k0.public_key_to_pem().unwrap();
+ let k1 = super::Rsa::public_key_from_pem(&k0pkey).unwrap();
+
+ let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
+
+ let mut emesg = vec![0; k0.size() as usize];
+ k0.private_encrypt(&msg, &mut emesg, Padding::PKCS1)
+ .unwrap();
+ let mut dmesg = vec![0; k1.size() as usize];
+ let len = k1
+ .public_decrypt(&emesg, &mut dmesg, Padding::PKCS1)
+ .unwrap();
+ assert_eq!(msg, &dmesg[..len]);
+ }
+
+ #[test]
+ fn test_public_encrypt() {
+ let k0 = super::Rsa::generate(512).unwrap();
+ let k0pkey = k0.private_key_to_pem().unwrap();
+ let k1 = super::Rsa::private_key_from_pem(&k0pkey).unwrap();
+
+ let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
+
+ let mut emesg = vec![0; k0.size() as usize];
+ k0.public_encrypt(&msg, &mut emesg, Padding::PKCS1).unwrap();
+ let mut dmesg = vec![0; k1.size() as usize];
+ let len = k1
+ .private_decrypt(&emesg, &mut dmesg, Padding::PKCS1)
+ .unwrap();
+ assert_eq!(msg, &dmesg[..len]);
+ }
+
+ #[test]
+ fn test_public_key_from_pem_pkcs1() {
+ let key = include_bytes!("../test/pkcs1.pem.pub");
+ Rsa::public_key_from_pem_pkcs1(key).unwrap();
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_public_key_from_pem_pkcs1_file_panic() {
+ let key = include_bytes!("../test/key.pem.pub");
+ Rsa::public_key_from_pem_pkcs1(key).unwrap();
+ }
+
+ #[test]
+ fn test_public_key_to_pem_pkcs1() {
+ let keypair = super::Rsa::generate(512).unwrap();
+ let pubkey_pem = keypair.public_key_to_pem_pkcs1().unwrap();
+ super::Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap();
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_public_key_from_pem_pkcs1_generate_panic() {
+ let keypair = super::Rsa::generate(512).unwrap();
+ let pubkey_pem = keypair.public_key_to_pem().unwrap();
+ super::Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap();
+ }
+
+ #[test]
+ fn test_pem_pkcs1_encrypt() {
+ let keypair = super::Rsa::generate(2048).unwrap();
+ let pubkey_pem = keypair.public_key_to_pem_pkcs1().unwrap();
+ let pubkey = super::Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap();
+ let msg = b"Hello, world!";
+
+ let mut encrypted = vec![0; pubkey.size() as usize];
+ let len = pubkey
+ .public_encrypt(msg, &mut encrypted, Padding::PKCS1)
+ .unwrap();
+ assert!(len > msg.len());
+ let mut decrypted = vec![0; keypair.size() as usize];
+ let len = keypair
+ .private_decrypt(&encrypted, &mut decrypted, Padding::PKCS1)
+ .unwrap();
+ assert_eq!(len, msg.len());
+ assert_eq!(&decrypted[..len], msg);
+ }
+
+ #[test]
+ fn test_pem_pkcs1_padding() {
+ let keypair = super::Rsa::generate(2048).unwrap();
+ let pubkey_pem = keypair.public_key_to_pem_pkcs1().unwrap();
+ let pubkey = super::Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap();
+ let msg = b"foo";
+
+ let mut encrypted1 = vec![0; pubkey.size() as usize];
+ let mut encrypted2 = vec![0; pubkey.size() as usize];
+ let len1 = pubkey
+ .public_encrypt(msg, &mut encrypted1, Padding::PKCS1)
+ .unwrap();
+ let len2 = pubkey
+ .public_encrypt(msg, &mut encrypted2, Padding::PKCS1)
+ .unwrap();
+ assert!(len1 > (msg.len() + 1));
+ assert_eq!(len1, len2);
+ assert_ne!(encrypted1, encrypted2);
+ }
+
+ #[test]
+ #[allow(clippy::redundant_clone)]
+ fn clone() {
+ let key = Rsa::generate(2048).unwrap();
+ drop(key.clone());
+ }
+
+ #[test]
+ fn generate_with_e() {
+ let e = BigNum::from_u32(0x10001).unwrap();
+ Rsa::generate_with_e(2048, &e).unwrap();
+ }
+}