boring_imp/
rsa.rs

1//! Rivest–Shamir–Adleman cryptosystem
2//!
3//! RSA is one of the earliest asymmetric public key encryption schemes.
4//! Like many other cryptosystems, RSA relies on the presumed difficulty of a hard
5//! mathematical problem, namely factorization of the product of two large prime
6//! numbers. At the moment there does not exist an algorithm that can factor such
7//! large numbers in reasonable time. RSA is used in a wide variety of
8//! applications including digital signatures and key exchanges such as
9//! establishing a TLS/SSL connection.
10//!
11//! The RSA acronym is derived from the first letters of the surnames of the
12//! algorithm's founding trio.
13//!
14//! # Example
15//!
16//! Generate a 2048-bit RSA key pair and use the public key to encrypt some data.
17//!
18//! ```rust
19//! use boring::rsa::{Rsa, Padding};
20//!
21//! let rsa = Rsa::generate(2048).unwrap();
22//! let data = b"foobar";
23//! let mut buf = vec![0; rsa.size() as usize];
24//! let encrypted_len = rsa.public_encrypt(data, &mut buf, Padding::PKCS1).unwrap();
25//! ```
26use crate::ffi;
27use foreign_types::{ForeignType, ForeignTypeRef};
28use libc::c_int;
29use std::fmt;
30use std::mem;
31use std::ptr;
32
33use crate::bn::{BigNum, BigNumRef};
34use crate::error::ErrorStack;
35use crate::pkey::{HasPrivate, HasPublic, Private, Public};
36use crate::{cvt, cvt_n, cvt_p};
37
38pub const EVP_PKEY_OP_SIGN: c_int = 1 << 3;
39pub const EVP_PKEY_OP_VERIFY: c_int = 1 << 4;
40pub const EVP_PKEY_OP_VERIFYRECOVER: c_int = 1 << 5;
41pub const EVP_PKEY_OP_SIGNCTX: c_int = 1 << 6;
42pub const EVP_PKEY_OP_VERIFYCTX: c_int = 1 << 7;
43pub const EVP_PKEY_OP_ENCRYPT: c_int = 1 << 8;
44pub const EVP_PKEY_OP_DECRYPT: c_int = 1 << 9;
45
46pub const EVP_PKEY_OP_TYPE_SIG: c_int = EVP_PKEY_OP_SIGN
47    | EVP_PKEY_OP_VERIFY
48    | EVP_PKEY_OP_VERIFYRECOVER
49    | EVP_PKEY_OP_SIGNCTX
50    | EVP_PKEY_OP_VERIFYCTX;
51
52pub const EVP_PKEY_OP_TYPE_CRYPT: c_int = EVP_PKEY_OP_ENCRYPT | EVP_PKEY_OP_DECRYPT;
53
54/// Type of encryption padding to use.
55///
56/// Random length padding is primarily used to prevent attackers from
57/// predicting or knowing the exact length of a plaintext message that
58/// can possibly lead to breaking encryption.
59#[derive(Debug, Copy, Clone, PartialEq, Eq)]
60pub struct Padding(c_int);
61
62impl Padding {
63    pub const NONE: Padding = Padding(ffi::RSA_NO_PADDING);
64    pub const PKCS1: Padding = Padding(ffi::RSA_PKCS1_PADDING);
65    pub const PKCS1_OAEP: Padding = Padding(ffi::RSA_PKCS1_OAEP_PADDING);
66    pub const PKCS1_PSS: Padding = Padding(ffi::RSA_PKCS1_PSS_PADDING);
67
68    /// Creates a `Padding` from an integer representation.
69    pub fn from_raw(value: c_int) -> Padding {
70        Padding(value)
71    }
72
73    /// Returns the integer representation of `Padding`.
74    #[allow(clippy::trivially_copy_pass_by_ref)]
75    pub fn as_raw(&self) -> c_int {
76        self.0
77    }
78}
79
80generic_foreign_type_and_impl_send_sync! {
81    type CType = ffi::RSA;
82    fn drop = ffi::RSA_free;
83
84    /// An RSA key.
85    pub struct Rsa<T>;
86
87    /// Reference to `RSA`
88    pub struct RsaRef<T>;
89}
90
91impl<T> Clone for Rsa<T> {
92    fn clone(&self) -> Rsa<T> {
93        (**self).to_owned()
94    }
95}
96
97impl<T> ToOwned for RsaRef<T> {
98    type Owned = Rsa<T>;
99
100    fn to_owned(&self) -> Rsa<T> {
101        unsafe {
102            ffi::RSA_up_ref(self.as_ptr());
103            Rsa::from_ptr(self.as_ptr())
104        }
105    }
106}
107
108impl<T> RsaRef<T>
109where
110    T: HasPrivate,
111{
112    private_key_to_pem! {
113        /// Serializes the private key to a PEM-encoded PKCS#1 RSAPrivateKey structure.
114        ///
115        /// The output will have a header of `-----BEGIN RSA PRIVATE KEY-----`.
116        ///
117        /// This corresponds to [`PEM_write_bio_RSAPrivateKey`].
118        ///
119        /// [`PEM_write_bio_RSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_RSAPrivateKey.html
120        private_key_to_pem,
121        /// Serializes the private key to a PEM-encoded encrypted PKCS#1 RSAPrivateKey structure.
122        ///
123        /// The output will have a header of `-----BEGIN RSA PRIVATE KEY-----`.
124        ///
125        /// This corresponds to [`PEM_write_bio_RSAPrivateKey`].
126        ///
127        /// [`PEM_write_bio_RSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_RSAPrivateKey.html
128        private_key_to_pem_passphrase,
129        ffi::PEM_write_bio_RSAPrivateKey
130    }
131
132    to_der! {
133        /// Serializes the private key to a DER-encoded PKCS#1 RSAPrivateKey structure.
134        ///
135        /// This corresponds to [`i2d_RSAPrivateKey`].
136        ///
137        /// [`i2d_RSAPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_RSAPrivateKey.html
138        private_key_to_der,
139        ffi::i2d_RSAPrivateKey
140    }
141
142    /// Decrypts data using the private key, returning the number of decrypted bytes.
143    ///
144    /// # Panics
145    ///
146    /// Panics if `self` has no private components, or if `to` is smaller
147    /// than `self.size()`.
148    pub fn private_decrypt(
149        &self,
150        from: &[u8],
151        to: &mut [u8],
152        padding: Padding,
153    ) -> Result<usize, ErrorStack> {
154        assert!(from.len() <= i32::MAX as usize);
155        assert!(to.len() >= self.size() as usize);
156
157        unsafe {
158            let len = cvt_n(ffi::RSA_private_decrypt(
159                from.len(),
160                from.as_ptr(),
161                to.as_mut_ptr(),
162                self.as_ptr(),
163                padding.0,
164            ))?;
165            Ok(len as usize)
166        }
167    }
168
169    /// Encrypts data using the private key, returning the number of encrypted bytes.
170    ///
171    /// # Panics
172    ///
173    /// Panics if `self` has no private components, or if `to` is smaller
174    /// than `self.size()`.
175    pub fn private_encrypt(
176        &self,
177        from: &[u8],
178        to: &mut [u8],
179        padding: Padding,
180    ) -> Result<usize, ErrorStack> {
181        assert!(from.len() <= i32::MAX as usize);
182        assert!(to.len() >= self.size() as usize);
183
184        unsafe {
185            let len = cvt_n(ffi::RSA_private_encrypt(
186                from.len(),
187                from.as_ptr(),
188                to.as_mut_ptr(),
189                self.as_ptr(),
190                padding.0,
191            ))?;
192            Ok(len as usize)
193        }
194    }
195
196    /// Returns a reference to the private exponent of the key.
197    ///
198    /// This corresponds to [`RSA_get0_key`].
199    ///
200    /// [`RSA_get0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html
201    pub fn d(&self) -> &BigNumRef {
202        unsafe {
203            let mut d = ptr::null();
204            RSA_get0_key(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut d);
205            BigNumRef::from_ptr(d as *mut _)
206        }
207    }
208
209    /// Returns a reference to the first factor of the exponent of the key.
210    ///
211    /// This corresponds to [`RSA_get0_factors`].
212    ///
213    /// [`RSA_get0_factors`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html
214    pub fn p(&self) -> Option<&BigNumRef> {
215        unsafe {
216            let mut p = ptr::null();
217            RSA_get0_factors(self.as_ptr(), &mut p, ptr::null_mut());
218            if p.is_null() {
219                None
220            } else {
221                Some(BigNumRef::from_ptr(p as *mut _))
222            }
223        }
224    }
225
226    /// Returns a reference to the second factor of the exponent of the key.
227    ///
228    /// This corresponds to [`RSA_get0_factors`].
229    ///
230    /// [`RSA_get0_factors`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html
231    pub fn q(&self) -> Option<&BigNumRef> {
232        unsafe {
233            let mut q = ptr::null();
234            RSA_get0_factors(self.as_ptr(), ptr::null_mut(), &mut q);
235            if q.is_null() {
236                None
237            } else {
238                Some(BigNumRef::from_ptr(q as *mut _))
239            }
240        }
241    }
242
243    /// Returns a reference to the first exponent used for CRT calculations.
244    ///
245    /// This corresponds to [`RSA_get0_crt_params`].
246    ///
247    /// [`RSA_get0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html
248    pub fn dmp1(&self) -> Option<&BigNumRef> {
249        unsafe {
250            let mut dp = ptr::null();
251            RSA_get0_crt_params(self.as_ptr(), &mut dp, ptr::null_mut(), ptr::null_mut());
252            if dp.is_null() {
253                None
254            } else {
255                Some(BigNumRef::from_ptr(dp as *mut _))
256            }
257        }
258    }
259
260    /// Returns a reference to the second exponent used for CRT calculations.
261    ///
262    /// This corresponds to [`RSA_get0_crt_params`].
263    ///
264    /// [`RSA_get0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html
265    pub fn dmq1(&self) -> Option<&BigNumRef> {
266        unsafe {
267            let mut dq = ptr::null();
268            RSA_get0_crt_params(self.as_ptr(), ptr::null_mut(), &mut dq, ptr::null_mut());
269            if dq.is_null() {
270                None
271            } else {
272                Some(BigNumRef::from_ptr(dq as *mut _))
273            }
274        }
275    }
276
277    /// Returns a reference to the coefficient used for CRT calculations.
278    ///
279    /// This corresponds to [`RSA_get0_crt_params`].
280    ///
281    /// [`RSA_get0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html
282    pub fn iqmp(&self) -> Option<&BigNumRef> {
283        unsafe {
284            let mut qi = ptr::null();
285            RSA_get0_crt_params(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut qi);
286            if qi.is_null() {
287                None
288            } else {
289                Some(BigNumRef::from_ptr(qi as *mut _))
290            }
291        }
292    }
293
294    /// Validates RSA parameters for correctness
295    ///
296    /// This corresponds to [`RSA_check_key`].
297    ///
298    /// [`RSA_check_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_check_key.html
299    #[allow(clippy::unnecessary_cast)]
300    pub fn check_key(&self) -> Result<bool, ErrorStack> {
301        unsafe {
302            let result = ffi::RSA_check_key(self.as_ptr()) as i32;
303            if result == -1 {
304                Err(ErrorStack::get())
305            } else {
306                Ok(result == 1)
307            }
308        }
309    }
310}
311
312impl<T> RsaRef<T>
313where
314    T: HasPublic,
315{
316    to_pem! {
317        /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure.
318        ///
319        /// The output will have a header of `-----BEGIN PUBLIC KEY-----`.
320        ///
321        /// This corresponds to [`PEM_write_bio_RSA_PUBKEY`].
322        ///
323        /// [`PEM_write_bio_RSA_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/pem.html
324        public_key_to_pem,
325        ffi::PEM_write_bio_RSA_PUBKEY
326    }
327
328    to_der! {
329        /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure.
330        ///
331        /// This corresponds to [`i2d_RSA_PUBKEY`].
332        ///
333        /// [`i2d_RSA_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_RSA_PUBKEY.html
334        public_key_to_der,
335        ffi::i2d_RSA_PUBKEY
336    }
337
338    to_pem! {
339        /// Serializes the public key into a PEM-encoded PKCS#1 RSAPublicKey structure.
340        ///
341        /// The output will have a header of `-----BEGIN RSA PUBLIC KEY-----`.
342        ///
343        /// This corresponds to [`PEM_write_bio_RSAPublicKey`].
344        ///
345        /// [`PEM_write_bio_RSAPublicKey`]: https://www.openssl.org/docs/man1.0.2/crypto/pem.html
346        public_key_to_pem_pkcs1,
347        ffi::PEM_write_bio_RSAPublicKey
348    }
349
350    to_der! {
351        /// Serializes the public key into a DER-encoded PKCS#1 RSAPublicKey structure.
352        ///
353        /// This corresponds to [`i2d_RSAPublicKey`].
354        ///
355        /// [`i2d_RSAPublicKey`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_RSAPublicKey.html
356        public_key_to_der_pkcs1,
357        ffi::i2d_RSAPublicKey
358    }
359
360    /// Returns the size of the modulus in bytes.
361    ///
362    /// This corresponds to [`RSA_size`].
363    ///
364    /// [`RSA_size`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_size.html
365    #[allow(clippy::unnecessary_cast)]
366    pub fn size(&self) -> u32 {
367        unsafe { ffi::RSA_size(self.as_ptr()) as u32 }
368    }
369
370    /// Decrypts data using the public key, returning the number of decrypted bytes.
371    ///
372    /// # Panics
373    ///
374    /// Panics if `to` is smaller than `self.size()`.
375    pub fn public_decrypt(
376        &self,
377        from: &[u8],
378        to: &mut [u8],
379        padding: Padding,
380    ) -> Result<usize, ErrorStack> {
381        assert!(from.len() <= i32::MAX as usize);
382        assert!(to.len() >= self.size() as usize);
383
384        unsafe {
385            let len = cvt_n(ffi::RSA_public_decrypt(
386                from.len(),
387                from.as_ptr(),
388                to.as_mut_ptr(),
389                self.as_ptr(),
390                padding.0,
391            ))?;
392            Ok(len as usize)
393        }
394    }
395
396    /// Encrypts data using the public key, returning the number of encrypted bytes.
397    ///
398    /// # Panics
399    ///
400    /// Panics if `to` is smaller than `self.size()`.
401    pub fn public_encrypt(
402        &self,
403        from: &[u8],
404        to: &mut [u8],
405        padding: Padding,
406    ) -> Result<usize, ErrorStack> {
407        assert!(from.len() <= i32::MAX as usize);
408        assert!(to.len() >= self.size() as usize);
409
410        unsafe {
411            let len = cvt_n(ffi::RSA_public_encrypt(
412                from.len(),
413                from.as_ptr(),
414                to.as_mut_ptr(),
415                self.as_ptr(),
416                padding.0,
417            ))?;
418            Ok(len as usize)
419        }
420    }
421
422    /// Returns a reference to the modulus of the key.
423    ///
424    /// This corresponds to [`RSA_get0_key`].
425    ///
426    /// [`RSA_get0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html
427    pub fn n(&self) -> &BigNumRef {
428        unsafe {
429            let mut n = ptr::null();
430            RSA_get0_key(self.as_ptr(), &mut n, ptr::null_mut(), ptr::null_mut());
431            BigNumRef::from_ptr(n as *mut _)
432        }
433    }
434
435    /// Returns a reference to the public exponent of the key.
436    ///
437    /// This corresponds to [`RSA_get0_key`].
438    ///
439    /// [`RSA_get0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html
440    pub fn e(&self) -> &BigNumRef {
441        unsafe {
442            let mut e = ptr::null();
443            RSA_get0_key(self.as_ptr(), ptr::null_mut(), &mut e, ptr::null_mut());
444            BigNumRef::from_ptr(e as *mut _)
445        }
446    }
447}
448
449impl Rsa<Public> {
450    /// Creates a new RSA key with only public components.
451    ///
452    /// `n` is the modulus common to both public and private key.
453    /// `e` is the public exponent.
454    ///
455    /// This corresponds to [`RSA_new`] and uses [`RSA_set0_key`].
456    ///
457    /// [`RSA_new`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_new.html
458    /// [`RSA_set0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_key.html
459    pub fn from_public_components(n: BigNum, e: BigNum) -> Result<Rsa<Public>, ErrorStack> {
460        unsafe {
461            let rsa = cvt_p(ffi::RSA_new())?;
462            RSA_set0_key(rsa, n.as_ptr(), e.as_ptr(), ptr::null_mut());
463            mem::forget((n, e));
464            Ok(Rsa::from_ptr(rsa))
465        }
466    }
467
468    from_pem! {
469        /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing an RSA key.
470        ///
471        /// The input should have a header of `-----BEGIN PUBLIC KEY-----`.
472        ///
473        /// This corresponds to [`PEM_read_bio_RSA_PUBKEY`].
474        ///
475        /// [`PEM_read_bio_RSA_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_RSA_PUBKEY.html
476        public_key_from_pem,
477        Rsa<Public>,
478        ffi::PEM_read_bio_RSA_PUBKEY
479    }
480
481    from_pem! {
482        /// Decodes a PEM-encoded PKCS#1 RSAPublicKey structure.
483        ///
484        /// The input should have a header of `-----BEGIN RSA PUBLIC KEY-----`.
485        ///
486        /// This corresponds to [`PEM_read_bio_RSAPublicKey`].
487        ///
488        /// [`PEM_read_bio_RSAPublicKey`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_RSAPublicKey.html
489        public_key_from_pem_pkcs1,
490        Rsa<Public>,
491        ffi::PEM_read_bio_RSAPublicKey
492    }
493
494    from_der! {
495        /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing an RSA key.
496        ///
497        /// This corresponds to [`d2i_RSA_PUBKEY`].
498        ///
499        /// [`d2i_RSA_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_RSA_PUBKEY.html
500        public_key_from_der,
501        Rsa<Public>,
502        ffi::d2i_RSA_PUBKEY,
503        ::libc::c_long
504    }
505
506    from_der! {
507        /// Decodes a DER-encoded PKCS#1 RSAPublicKey structure.
508        ///
509        /// This corresponds to [`d2i_RSAPublicKey`].
510        ///
511        /// [`d2i_RSAPublicKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_RSA_PUBKEY.html
512        public_key_from_der_pkcs1,
513        Rsa<Public>,
514        ffi::d2i_RSAPublicKey,
515        ::libc::c_long
516    }
517}
518
519pub struct RsaPrivateKeyBuilder {
520    rsa: Rsa<Private>,
521}
522
523impl RsaPrivateKeyBuilder {
524    /// Creates a new `RsaPrivateKeyBuilder`.
525    ///
526    /// `n` is the modulus common to both public and private key.
527    /// `e` is the public exponent and `d` is the private exponent.
528    ///
529    /// This corresponds to [`RSA_new`] and uses [`RSA_set0_key`].
530    ///
531    /// [`RSA_new`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_new.html
532    /// [`RSA_set0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_key.html
533    pub fn new(n: BigNum, e: BigNum, d: BigNum) -> Result<RsaPrivateKeyBuilder, ErrorStack> {
534        unsafe {
535            let rsa = cvt_p(ffi::RSA_new())?;
536            RSA_set0_key(rsa, n.as_ptr(), e.as_ptr(), d.as_ptr());
537            mem::forget((n, e, d));
538            Ok(RsaPrivateKeyBuilder {
539                rsa: Rsa::from_ptr(rsa),
540            })
541        }
542    }
543
544    /// Sets the factors of the Rsa key.
545    ///
546    /// `p` and `q` are the first and second factors of `n`.
547    ///
548    /// This correspond to [`RSA_set0_factors`].
549    ///
550    /// [`RSA_set0_factors`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_factors.html
551    // FIXME should be infallible
552    pub fn set_factors(self, p: BigNum, q: BigNum) -> Result<RsaPrivateKeyBuilder, ErrorStack> {
553        unsafe {
554            RSA_set0_factors(self.rsa.as_ptr(), p.as_ptr(), q.as_ptr());
555            mem::forget((p, q));
556        }
557        Ok(self)
558    }
559
560    /// Sets the Chinese Remainder Theorem params of the Rsa key.
561    ///
562    /// `dmp1`, `dmq1`, and `iqmp` are the exponents and coefficient for
563    /// CRT calculations which is used to speed up RSA operations.
564    ///
565    /// This correspond to [`RSA_set0_crt_params`].
566    ///
567    /// [`RSA_set0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_crt_params.html
568    // FIXME should be infallible
569    pub fn set_crt_params(
570        self,
571        dmp1: BigNum,
572        dmq1: BigNum,
573        iqmp: BigNum,
574    ) -> Result<RsaPrivateKeyBuilder, ErrorStack> {
575        unsafe {
576            RSA_set0_crt_params(
577                self.rsa.as_ptr(),
578                dmp1.as_ptr(),
579                dmq1.as_ptr(),
580                iqmp.as_ptr(),
581            );
582            mem::forget((dmp1, dmq1, iqmp));
583        }
584        Ok(self)
585    }
586
587    /// Returns the Rsa key.
588    pub fn build(self) -> Rsa<Private> {
589        self.rsa
590    }
591}
592
593impl Rsa<Private> {
594    /// Creates a new RSA key with private components (public components are assumed).
595    ///
596    /// This a convenience method over
597    /// `Rsa::build(n, e, d)?.set_factors(p, q)?.set_crt_params(dmp1, dmq1, iqmp)?.build()`
598    #[allow(clippy::too_many_arguments, clippy::many_single_char_names)]
599    pub fn from_private_components(
600        n: BigNum,
601        e: BigNum,
602        d: BigNum,
603        p: BigNum,
604        q: BigNum,
605        dmp1: BigNum,
606        dmq1: BigNum,
607        iqmp: BigNum,
608    ) -> Result<Rsa<Private>, ErrorStack> {
609        Ok(RsaPrivateKeyBuilder::new(n, e, d)?
610            .set_factors(p, q)?
611            .set_crt_params(dmp1, dmq1, iqmp)?
612            .build())
613    }
614
615    /// Generates a public/private key pair with the specified size.
616    ///
617    /// The public exponent will be 65537.
618    ///
619    /// This corresponds to [`RSA_generate_key_ex`].
620    ///
621    /// [`RSA_generate_key_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_generate_key_ex.html
622    pub fn generate(bits: u32) -> Result<Rsa<Private>, ErrorStack> {
623        let e = BigNum::from_u32(ffi::RSA_F4 as u32)?;
624        Rsa::generate_with_e(bits, &e)
625    }
626
627    /// Generates a public/private key pair with the specified size and a custom exponent.
628    ///
629    /// Unless you have specific needs and know what you're doing, use `Rsa::generate` instead.
630    ///
631    /// This corresponds to [`RSA_generate_key_ex`].
632    ///
633    /// [`RSA_generate_key_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_generate_key_ex.html
634    pub fn generate_with_e(bits: u32, e: &BigNumRef) -> Result<Rsa<Private>, ErrorStack> {
635        unsafe {
636            let rsa = Rsa::from_ptr(cvt_p(ffi::RSA_new())?);
637            cvt(ffi::RSA_generate_key_ex(
638                rsa.0,
639                bits as c_int,
640                e.as_ptr(),
641                ptr::null_mut(),
642            ))?;
643            Ok(rsa)
644        }
645    }
646
647    // FIXME these need to identify input formats
648    private_key_from_pem! {
649        /// Deserializes a private key from a PEM-encoded PKCS#1 RSAPrivateKey structure.
650        ///
651        /// This corresponds to [`PEM_read_bio_RSAPrivateKey`].
652        ///
653        /// [`PEM_read_bio_RSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_RSAPrivateKey.html
654        private_key_from_pem,
655
656        /// Deserializes a private key from a PEM-encoded encrypted PKCS#1 RSAPrivateKey structure.
657        ///
658        /// This corresponds to [`PEM_read_bio_RSAPrivateKey`].
659        ///
660        /// [`PEM_read_bio_RSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_RSAPrivateKey.html
661        private_key_from_pem_passphrase,
662
663        /// Deserializes a private key from a PEM-encoded encrypted PKCS#1 RSAPrivateKey structure.
664        ///
665        /// The callback should fill the password into the provided buffer and return its length.
666        ///
667        /// This corresponds to [`PEM_read_bio_RSAPrivateKey`].
668        ///
669        /// [`PEM_read_bio_RSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_RSAPrivateKey.html
670        private_key_from_pem_callback,
671        Rsa<Private>,
672        ffi::PEM_read_bio_RSAPrivateKey
673    }
674
675    from_der! {
676        /// Decodes a DER-encoded PKCS#1 RSAPrivateKey structure.
677        ///
678        /// This corresponds to [`d2i_RSAPrivateKey`].
679        ///
680        /// [`d2i_RSAPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_RSA_PUBKEY.html
681        private_key_from_der,
682        Rsa<Private>,
683        ffi::d2i_RSAPrivateKey,
684        ::libc::c_long
685    }
686}
687
688impl<T> fmt::Debug for Rsa<T> {
689    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
690        write!(f, "Rsa")
691    }
692}
693
694use crate::ffi::{
695    RSA_get0_crt_params, RSA_get0_factors, RSA_get0_key, RSA_set0_crt_params, RSA_set0_factors,
696    RSA_set0_key,
697};
698
699#[cfg(test)]
700mod test {
701    use crate::symm::Cipher;
702
703    use super::*;
704
705    #[test]
706    fn test_from_password() {
707        let key = include_bytes!("../test/rsa-encrypted.pem");
708        Rsa::private_key_from_pem_passphrase(key, b"mypass").unwrap();
709    }
710
711    #[test]
712    fn test_from_password_callback() {
713        let mut password_queried = false;
714        let key = include_bytes!("../test/rsa-encrypted.pem");
715        Rsa::private_key_from_pem_callback(key, |password| {
716            password_queried = true;
717            password[..6].copy_from_slice(b"mypass");
718            Ok(6)
719        })
720        .unwrap();
721
722        assert!(password_queried);
723    }
724
725    #[test]
726    fn test_to_password() {
727        let key = Rsa::generate(2048).unwrap();
728        let pem = key
729            .private_key_to_pem_passphrase(Cipher::aes_128_cbc(), b"foobar")
730            .unwrap();
731        Rsa::private_key_from_pem_passphrase(&pem, b"foobar").unwrap();
732        assert!(Rsa::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err());
733    }
734
735    #[test]
736    fn test_public_encrypt_private_decrypt_with_padding() {
737        let key = include_bytes!("../test/rsa.pem.pub");
738        let public_key = Rsa::public_key_from_pem(key).unwrap();
739
740        let mut result = vec![0; public_key.size() as usize];
741        let original_data = b"This is test";
742        let len = public_key
743            .public_encrypt(original_data, &mut result, Padding::PKCS1)
744            .unwrap();
745        assert_eq!(len, 256);
746
747        let pkey = include_bytes!("../test/rsa.pem");
748        let private_key = Rsa::private_key_from_pem(pkey).unwrap();
749        let mut dec_result = vec![0; private_key.size() as usize];
750        let len = private_key
751            .private_decrypt(&result, &mut dec_result, Padding::PKCS1)
752            .unwrap();
753
754        assert_eq!(&dec_result[..len], original_data);
755    }
756
757    #[test]
758    fn test_private_encrypt() {
759        let k0 = super::Rsa::generate(512).unwrap();
760        let k0pkey = k0.public_key_to_pem().unwrap();
761        let k1 = super::Rsa::public_key_from_pem(&k0pkey).unwrap();
762
763        let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
764
765        let mut emesg = vec![0; k0.size() as usize];
766        k0.private_encrypt(&msg, &mut emesg, Padding::PKCS1)
767            .unwrap();
768        let mut dmesg = vec![0; k1.size() as usize];
769        let len = k1
770            .public_decrypt(&emesg, &mut dmesg, Padding::PKCS1)
771            .unwrap();
772        assert_eq!(msg, &dmesg[..len]);
773    }
774
775    #[test]
776    fn test_public_encrypt() {
777        let k0 = super::Rsa::generate(512).unwrap();
778        let k0pkey = k0.private_key_to_pem().unwrap();
779        let k1 = super::Rsa::private_key_from_pem(&k0pkey).unwrap();
780
781        let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
782
783        let mut emesg = vec![0; k0.size() as usize];
784        k0.public_encrypt(&msg, &mut emesg, Padding::PKCS1).unwrap();
785        let mut dmesg = vec![0; k1.size() as usize];
786        let len = k1
787            .private_decrypt(&emesg, &mut dmesg, Padding::PKCS1)
788            .unwrap();
789        assert_eq!(msg, &dmesg[..len]);
790    }
791
792    #[test]
793    fn test_public_key_from_pem_pkcs1() {
794        let key = include_bytes!("../test/pkcs1.pem.pub");
795        Rsa::public_key_from_pem_pkcs1(key).unwrap();
796    }
797
798    #[test]
799    #[should_panic]
800    fn test_public_key_from_pem_pkcs1_file_panic() {
801        let key = include_bytes!("../test/key.pem.pub");
802        Rsa::public_key_from_pem_pkcs1(key).unwrap();
803    }
804
805    #[test]
806    fn test_public_key_to_pem_pkcs1() {
807        let keypair = super::Rsa::generate(512).unwrap();
808        let pubkey_pem = keypair.public_key_to_pem_pkcs1().unwrap();
809        super::Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap();
810    }
811
812    #[test]
813    #[should_panic]
814    fn test_public_key_from_pem_pkcs1_generate_panic() {
815        let keypair = super::Rsa::generate(512).unwrap();
816        let pubkey_pem = keypair.public_key_to_pem().unwrap();
817        super::Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap();
818    }
819
820    #[test]
821    fn test_pem_pkcs1_encrypt() {
822        let keypair = super::Rsa::generate(2048).unwrap();
823        let pubkey_pem = keypair.public_key_to_pem_pkcs1().unwrap();
824        let pubkey = super::Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap();
825        let msg = b"Hello, world!";
826
827        let mut encrypted = vec![0; pubkey.size() as usize];
828        let len = pubkey
829            .public_encrypt(msg, &mut encrypted, Padding::PKCS1)
830            .unwrap();
831        assert!(len > msg.len());
832        let mut decrypted = vec![0; keypair.size() as usize];
833        let len = keypair
834            .private_decrypt(&encrypted, &mut decrypted, Padding::PKCS1)
835            .unwrap();
836        assert_eq!(len, msg.len());
837        assert_eq!(&decrypted[..len], msg);
838    }
839
840    #[test]
841    fn test_pem_pkcs1_padding() {
842        let keypair = super::Rsa::generate(2048).unwrap();
843        let pubkey_pem = keypair.public_key_to_pem_pkcs1().unwrap();
844        let pubkey = super::Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap();
845        let msg = b"foo";
846
847        let mut encrypted1 = vec![0; pubkey.size() as usize];
848        let mut encrypted2 = vec![0; pubkey.size() as usize];
849        let len1 = pubkey
850            .public_encrypt(msg, &mut encrypted1, Padding::PKCS1)
851            .unwrap();
852        let len2 = pubkey
853            .public_encrypt(msg, &mut encrypted2, Padding::PKCS1)
854            .unwrap();
855        assert!(len1 > (msg.len() + 1));
856        assert_eq!(len1, len2);
857        assert_ne!(encrypted1, encrypted2);
858    }
859
860    #[test]
861    #[allow(clippy::redundant_clone)]
862    fn clone() {
863        let key = Rsa::generate(2048).unwrap();
864        drop(key.clone());
865    }
866
867    #[test]
868    fn generate_with_e() {
869        let e = BigNum::from_u32(0x10001).unwrap();
870        Rsa::generate_with_e(2048, &e).unwrap();
871    }
872}