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