Skip to content

Commit

Permalink
Adds a RsaPrivateKey::from_primes method
Browse files Browse the repository at this point in the history
This is used on Yubico HSM for import/export under wrap as well as when
importing a key unsealed.
  • Loading branch information
baloo committed Nov 21, 2023
1 parent 00eaa91 commit 649f3ee
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 1 deletion.
32 changes: 32 additions & 0 deletions src/algorithms/rsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<BigUint> {
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;
Expand Down
67 changes: 66 additions & 1 deletion src/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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<BigUint>, public_exponent: BigUint) -> Result<RsaPrivateKey> {
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,
Expand Down Expand Up @@ -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
"
)
);
}
}

0 comments on commit 649f3ee

Please sign in to comment.