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}