Implement RSA key precomputation

This commit is contained in:
BlackHoleFox
2020-06-08 21:48:25 -05:00
parent acc96e988f
commit 0f907ebd5c
3 changed files with 66 additions and 14 deletions
Generated
+3
View File
@@ -1064,6 +1064,9 @@ dependencies = [
"log", "log",
"nom", "nom",
"num-bigint", "num-bigint",
"num-bigint-dig",
"num-integer",
"num-traits",
"p256", "p256",
"p384", "p384",
"pbkdf2", "pbkdf2",
+4 -1
View File
@@ -31,7 +31,10 @@ getrandom = "0.1"
hmac = "0.7" hmac = "0.7"
log = "0.4" log = "0.4"
nom = "5" nom = "5"
num-bigint = { version = "0.2", features = ["rand"] } num-bigint_rsa = { version = "0.6", features = ["rand"], package = "num-bigint-dig" }
num-bigint = { version = "0.2", features = ["rand"] }
num-traits = "0.2"
num-integer = "0.1"
pbkdf2 = "0.3" pbkdf2 = "0.3"
p256 = "0.2" p256 = "0.2"
p384 = "0.1" p384 = "0.1"
+59 -13
View File
@@ -58,6 +58,12 @@ use crate::{
}; };
use elliptic_curve::weierstrass::PublicKey as EcPublicKey; use elliptic_curve::weierstrass::PublicKey as EcPublicKey;
use log::{error, warn}; use log::{error, warn};
#[cfg(feature = "untested")]
use num_bigint_rsa::traits::ModInverse;
#[cfg(feature = "untested")]
use num_integer::Integer;
#[cfg(feature = "untested")]
use num_traits::{FromPrimitive, One};
use rsa::{BigUint, RSAPublicKey}; use rsa::{BigUint, RSAPublicKey};
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
use zeroize::Zeroizing; use zeroize::Zeroizing;
@@ -72,6 +78,9 @@ const TAG_ECC_POINT: u8 = 0x86;
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
const KEYDATA_LEN: usize = 1024; const KEYDATA_LEN: usize = 1024;
#[cfg(feature = "untested")]
const KEYDATA_RSA_EXP: u64 = 65537;
/// Slot identifiers. /// Slot identifiers.
/// <https://developers.yubico.com/PIV/Introduction/Certificate_slots.html> /// <https://developers.yubico.com/PIV/Introduction/Certificate_slots.html>
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
@@ -703,21 +712,58 @@ fn write_key(
/// The key data that makes up an RSA key. /// The key data that makes up an RSA key.
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
pub struct RsaKeyData<'a> { pub struct RsaKeyData {
/// The secret prime `p`. /// The secret prime `p`.
pub p: &'a [u8], p: Zeroizing<Vec<u8>>,
/// The secret prime, `q`. /// The secret prime, `q`.
pub q: &'a [u8], q: Zeroizing<Vec<u8>>,
/// D mod (P-1) /// D mod (P-1)
pub dp: &'a [u8], dp: Zeroizing<Vec<u8>>,
/// D mod (Q-1) /// D mod (Q-1)
pub dq: &'a [u8], dq: Zeroizing<Vec<u8>>,
/// Q^-1 mod P /// Q^-1 mod P
pub qinv: &'a [u8], qinv: Zeroizing<Vec<u8>>,
} }
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
impl RsaKeyData<'_> { impl RsaKeyData {
/// Generates a new RSA key data set from two randomly generated, secret, primes.
///
/// Panics if `secret_p` or `secret_q` are invalid primes.
pub fn new(secret_p: &[u8], secret_q: &[u8]) -> Self {
let p = BigUint::from_bytes_be(secret_p);
let q = BigUint::from_bytes_be(secret_q);
let totient = {
let p_t = &p - BigUint::one();
let q_t = &p - BigUint::one();
p_t.lcm(&q_t)
};
let exp = BigUint::from_u64(KEYDATA_RSA_EXP).unwrap();
let d = exp.mod_inverse(&totient).unwrap();
let d = d.to_biguint().unwrap();
// We calculate the optimization values ahead of time, instead of making the user
// do so.
let dp = &d % (&p - BigUint::one());
let dq = &d % (&q - BigUint::one());
let qinv = q.clone().mod_inverse(&p).unwrap();
let (_, qinv) = qinv.to_bytes_be();
RsaKeyData {
p: Zeroizing::new(p.to_bytes_be()),
q: Zeroizing::new(q.to_bytes_be()),
dp: Zeroizing::new(dp.to_bytes_be()),
dq: Zeroizing::new(dq.to_bytes_be()),
qinv: Zeroizing::new(qinv),
}
}
fn total_len(&self) -> usize { fn total_len(&self) -> usize {
self.p.len() + self.q.len() + self.dp.len() + self.qinv.len() self.p.len() + self.q.len() + self.dp.len() + self.qinv.len()
} }
@@ -731,7 +777,7 @@ pub fn import_rsa_key(
yubikey: &mut YubiKey, yubikey: &mut YubiKey,
slot: SlotId, slot: SlotId,
algorithm: AlgorithmId, algorithm: AlgorithmId,
key_data: RsaKeyData<'_>, key_data: RsaKeyData,
touch_policy: TouchPolicy, touch_policy: TouchPolicy,
pin_policy: PinPolicy, pin_policy: PinPolicy,
) -> Result<(), Error> { ) -> Result<(), Error> {
@@ -745,11 +791,11 @@ pub fn import_rsa_key(
} }
let params = vec![ let params = vec![
key_data.p, key_data.p.as_slice(),
key_data.q, key_data.q.as_slice(),
key_data.dp, key_data.dp.as_slice(),
key_data.dq, key_data.dq.as_slice(),
key_data.qinv, key_data.qinv.as_slice(),
]; ];
write_key(yubikey, slot, params, pin_policy, touch_policy, algorithm)?; write_key(yubikey, slot, params, pin_policy, touch_policy, algorithm)?;