diff --git a/src/algorithms/rsa.rs b/src/algorithms/rsa.rs index 6473f378..50925e70 100644 --- a/src/algorithms/rsa.rs +++ b/src/algorithms/rsa.rs @@ -245,6 +245,38 @@ pub fn recover_primes(n: &BigUint, e: &BigUint, d: &BigUint) -> Result<(BigUint, Ok((p, q)) } +/// Compute the modulus of a key from its primes. +pub(crate) fn compute_modulus(primes: &[BigUint]) -> BigUint { + let mut n = BigUint::one(); + + for prime in primes { + n *= prime; + } + + n +} + +/// Compute the private exponent from its primes and public exponent +pub(crate) fn compute_private_exponent(primes: &[BigUint], exp: &BigUint) -> Result { + let mut totient = BigUint::one(); + + for prime in primes { + totient *= prime - BigUint::one(); + } + + std::println!("exp {:?}", exp.to_bytes_be()); + std::println!("totient {:?}", totient.to_bytes_be()); + if let Some(d) = exp.mod_inverse(totient) { + std::println!("d {:?}", d); + std::println!("d {:?}", d.to_bytes_be()); + std::println!("d {:?}", d.to_biguint().unwrap().to_bytes_be()); + Ok(d.to_biguint().unwrap()) + } else { + // `exp` evenly divides `totient` + Err(Error::InvalidPrime) + } +} + #[cfg(test)] mod tests { use num_traits::FromPrimitive; diff --git a/src/key.rs b/src/key.rs index 9589e1d3..12de6343 100644 --- a/src/key.rs +++ b/src/key.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; use zeroize::{Zeroize, ZeroizeOnDrop}; use crate::algorithms::generate::generate_multi_prime_key_with_exp; -use crate::algorithms::rsa::recover_primes; +use crate::algorithms::rsa::{compute_modulus, compute_private_exponent, recover_primes}; use crate::dummy_rng::DummyRng; use crate::errors::{Error, Result}; @@ -279,6 +279,29 @@ impl RsaPrivateKey { Ok(k) } + /// Constructs an RSA key pair from its primes. + /// + /// This will rebuild the private exponent and the modulus. + pub fn from_primes(primes: Vec, public_exponent: BigUint) -> Result { + if primes.len() < 2 { + return Err(Error::NprimesTooSmall); + } + + // Makes sure that primes is pairwise unequal. + for (i, prime1) in primes.iter().enumerate() { + for prime2 in primes.iter().take(i) { + if prime1 == prime2 { + return Err(Error::InvalidPrime); + } + } + } + + let n = compute_modulus(&primes); + let d = compute_private_exponent(&primes, &public_exponent)?; + + Self::from_components(n, public_exponent, d, primes) + } + /// Get the public key from the private key, cloning `n` and `e`. /// /// Generally this is not needed since `RsaPrivateKey` implements the `PublicKey` trait, @@ -753,4 +776,46 @@ mod tests { Error::ModulusTooLarge ); } + + #[test] + fn build_key_from_primes() { + let primes = vec![ + BigUint::from_bytes_be(&hex!("00d3f729b732696acc814a007b27bc786c11c3ebee55b7935d4bde4dc50032b496a082f0ccc37472c2f8c6344cbd570808f381c80d0b01107069368ad32a2e0b0ca4174b17b15f21093f917158cb46a96c113fa421ca73f3c6a5e5e93c68ad7255f59c792bbc40c135fb2dfe488bdf266aba6c0c38733f07a50d14e0557cee0c51")), + BigUint::from_bytes_be(&hex!("00c8936e1179ef258bb3cea300deae7da9660cff7f6f0a1cceea74327921a1bf35f7548e3274f1536d0acc29b54b2f6048c412ce5dbf668735ab0eed1808f6678a108d7f0b6445b3a69cb897a08e3190388c6c559a72f12d74e62a283532d2ea20d0eb98e13c5add9067879638868bd6badea24f93d02bc13b8edcf29b720e6381")), + ]; + + let exp = BigUint::from_u64(RsaPrivateKey::EXP).expect("invalid static exponent"); + let key = + RsaPrivateKey::from_primes(primes, exp).expect("failed to import key from primes"); + + assert_eq!(key.n().to_bytes_be(), &hex!("a6132aa6bfe0a059ab4bf3ad9b31f869f96ed7e653119311f58a1a60c0ac11aabc30a965fc5ae334612ce13b1f5903fae8d4a49a4d3a0f86d9116aa0a6323907cb9295cf6be3b1a0d5fe70017d329c088a4a741893afc558a47fde7b90277a14987badcdba246bfc96ae481169d5e64ec73ae825eca38bd3ccbb6e533a4c46c53a8260122a4e0e0e2fb6377141ab66889a000513e602b7d232a592490e35764713f41e92f91b3777090f0e9585c2a14b18bc7ad91da50507cd9a2680bed8d4e0342a030a1a326d72509d3d2fb915091fee79aac9a3b2a2df63d397634ca54235e5b92f176597a698c26832a89917683f239e73ee5dcaa4332ff6f7efc12587d1")); + + println!("dp: {:?}", key.dp().unwrap().to_bytes_be()); + println!("dq: {:?}", key.dq().unwrap().to_bytes_be()); + println!("qinv: {:?}", key.qinv().unwrap().to_bytes_be()); + assert_eq!( + key.d().to_bytes_be(), + &hex!( + " + 1a07a707bbcb5956b4a292ef030432 + 0b6a2d1569e45b3cd1f3ca5198189a + dfaa03151d77feb5c026d594533911 + 10c2aef10f633d4c1d6d91953445a2 + 286a76c5e20277b8ab106526f06390 + eaaad4e3dff2ccf8a561808b4df97a + 91448cb3a34ed7178b865346a22654 + f7bc13fea2a81670e3aabf46f7db52 + b7242986a1fc929ad6879fbce52135 + 32f0b5021bcdcdabd25fe941fbe7fa + 69587ad40a5febecc896aa1d5265b6 + 2eba328789a3a37a5d96108049e063 + ea68165cdacf8b0da578006fc4acfc + de38b878d901a288ec7ccff7353cd5 + 008b391dacd4215d64011de2ca9fca + 23c88979cb86ee52518cb865436105 + ffd1d5f6826bc3d48d9ec0cdafe301 +" + ) + ); + } }