Implement RSA key precomputation
This commit is contained in:
Generated
+3
@@ -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",
|
||||||
|
|||||||
@@ -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_rsa = { version = "0.6", features = ["rand"], package = "num-bigint-dig" }
|
||||||
num-bigint = { version = "0.2", features = ["rand"] }
|
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
@@ -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)?;
|
||||||
|
|||||||
Reference in New Issue
Block a user