diff options
Diffstat (limited to 'vendor/openssl/src/rsa.rs')
-rw-r--r-- | vendor/openssl/src/rsa.rs | 852 |
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(); + } +} |