rsa/src/key.rs
2019-03-18 09:29:05 -07:00

611 lines
18 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use clear_on_drop::clear::Clear;
use num_bigint::traits::ModInverse;
use num_bigint::Sign::Plus;
use num_bigint::{BigInt, BigUint};
use num_traits::{FromPrimitive, One};
use rand::{Rng, ThreadRng};
#[cfg(feature = "serde1")]
use serde::{Deserialize, Serialize};
use crate::algorithms::generate_multi_prime_key;
use crate::errors::{Error, Result};
use crate::hash::Hash;
use crate::padding::PaddingScheme;
use crate::pkcs1v15;
lazy_static! {
static ref MIN_PUB_EXPONENT: BigUint = BigUint::from_u64(2).unwrap();
static ref MAX_PUB_EXPONENT: BigUint = BigUint::from_u64(1 << (31 - 1)).unwrap();
}
/// Represents the public part of an RSA key.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct RSAPublicKey {
n: BigUint,
e: BigUint,
}
/// Represents a whole RSA key, public and private parts.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct RSAPrivateKey {
/// Modulus
n: BigUint,
/// Public exponent
e: BigUint,
/// Private exponent
d: BigUint,
/// Prime factors of N, contains >= 2 elements.
primes: Vec<BigUint>,
/// precomputed values to speed up private operations
#[cfg_attr(feature = "serde1", serde(skip))]
pub(crate) precomputed: Option<PrecomputedValues>,
}
impl PartialEq for RSAPrivateKey {
#[inline]
fn eq(&self, other: &RSAPrivateKey) -> bool {
self.n == other.n && self.e == other.e && self.d == other.d && self.primes == other.primes
}
}
impl Eq for RSAPrivateKey {}
impl Drop for RSAPrivateKey {
#[inline]
fn drop(&mut self) {
self.d.clear();
self.primes.clear();
self.precomputed.clear();
}
}
#[derive(Debug, Clone)]
pub(crate) struct PrecomputedValues {
/// D mod (P-1)
pub(crate) dp: BigUint,
/// D mod (Q-1)
pub(crate) dq: BigUint,
/// Q^-1 mod P
pub(crate) qinv: BigInt,
/// CRTValues is used for the 3rd and subsequent primes. Due to a
/// historical accident, the CRT for the first two primes is handled
/// differently in PKCS#1 and interoperability is sufficiently
/// important that we mirror this.
pub(crate) crt_values: Vec<CRTValue>,
}
impl Drop for PrecomputedValues {
#[inline]
fn drop(&mut self) {
self.dp.clear();
self.dq.clear();
self.qinv.clear();
self.crt_values.clear();
}
}
/// Contains the precomputed Chinese remainder theorem values.
#[derive(Debug, Clone)]
pub(crate) struct CRTValue {
/// D mod (prime - 1)
pub(crate) exp: BigInt,
/// R·Coeff ≡ 1 mod Prime.
pub(crate) coeff: BigInt,
/// product of primes prior to this (inc p and q)
pub(crate) r: BigInt,
}
impl From<RSAPrivateKey> for RSAPublicKey {
fn from(private_key: RSAPrivateKey) -> Self {
let n = private_key.n.clone();
let e = private_key.e.clone();
RSAPublicKey { n, e }
}
}
/// Generic trait for operations on a public key.
pub trait PublicKey {
/// Returns the modulus of the key.
fn n(&self) -> &BigUint;
/// Returns the public exponent of the key.
fn e(&self) -> &BigUint;
/// Returns the modulus size in bytes. Raw signatures and ciphertexts for
/// or by this public key will have the same size.
fn size(&self) -> usize {
(self.n().bits() + 7) / 8
}
/// Encrypt the given message.
fn encrypt<R: Rng>(&self, rng: &mut R, padding: PaddingScheme, msg: &[u8]) -> Result<Vec<u8>>;
/// Verify a signed message.
/// `hashed`must be the result of hashing the input using the hashing function
/// passed in through `hash`.
/// If the message is valid `Ok(())` is returned, otherwiese an `Err` indicating failure.
fn verify<H: Hash>(
&self,
padding: PaddingScheme,
hash: Option<&H>,
hashed: &[u8],
sig: &[u8],
) -> Result<()>;
}
impl PublicKey for RSAPublicKey {
fn n(&self) -> &BigUint {
&self.n
}
fn e(&self) -> &BigUint {
&self.e
}
fn encrypt<R: Rng>(&self, rng: &mut R, padding: PaddingScheme, msg: &[u8]) -> Result<Vec<u8>> {
match padding {
PaddingScheme::PKCS1v15 => pkcs1v15::encrypt(rng, self, msg),
PaddingScheme::OAEP => unimplemented!("not yet implemented"),
_ => Err(Error::InvalidPaddingScheme),
}
}
fn verify<H: Hash>(
&self,
padding: PaddingScheme,
hash: Option<&H>,
hashed: &[u8],
sig: &[u8],
) -> Result<()> {
match padding {
PaddingScheme::PKCS1v15 => pkcs1v15::verify(self, hash, hashed, sig),
PaddingScheme::PSS => unimplemented!("not yet implemented"),
_ => Err(Error::InvalidPaddingScheme),
}
}
}
impl RSAPublicKey {
/// Create a new key from its components.
pub fn new(n: BigUint, e: BigUint) -> Result<Self> {
let k = RSAPublicKey { n, e };
check_public(&k)?;
Ok(k)
}
}
impl<'a> PublicKey for &'a RSAPublicKey {
fn n(&self) -> &BigUint {
&self.n
}
fn e(&self) -> &BigUint {
&self.e
}
fn encrypt<R: Rng>(&self, rng: &mut R, padding: PaddingScheme, msg: &[u8]) -> Result<Vec<u8>> {
(*self).encrypt(rng, padding, msg)
}
fn verify<H: Hash>(
&self,
padding: PaddingScheme,
hash: Option<&H>,
hashed: &[u8],
sig: &[u8],
) -> Result<()> {
(*self).verify(padding, hash, hashed, sig)
}
}
impl PublicKey for RSAPrivateKey {
fn n(&self) -> &BigUint {
&self.n
}
fn e(&self) -> &BigUint {
&self.e
}
fn encrypt<R: Rng>(&self, rng: &mut R, padding: PaddingScheme, msg: &[u8]) -> Result<Vec<u8>> {
match padding {
PaddingScheme::PKCS1v15 => pkcs1v15::encrypt(rng, self, msg),
PaddingScheme::OAEP => unimplemented!("not yet implemented"),
_ => Err(Error::InvalidPaddingScheme),
}
}
fn verify<H: Hash>(
&self,
padding: PaddingScheme,
hash: Option<&H>,
hashed: &[u8],
sig: &[u8],
) -> Result<()> {
match padding {
PaddingScheme::PKCS1v15 => pkcs1v15::verify(self, hash, hashed, sig),
PaddingScheme::PSS => unimplemented!("not yet implemented"),
_ => Err(Error::InvalidPaddingScheme),
}
}
}
impl<'a> PublicKey for &'a RSAPrivateKey {
fn n(&self) -> &BigUint {
&self.n
}
fn e(&self) -> &BigUint {
&self.e
}
fn encrypt<R: Rng>(&self, rng: &mut R, padding: PaddingScheme, msg: &[u8]) -> Result<Vec<u8>> {
(*self).encrypt(rng, padding, msg)
}
fn verify<H: Hash>(
&self,
padding: PaddingScheme,
hash: Option<&H>,
hashed: &[u8],
sig: &[u8],
) -> Result<()> {
(*self).verify(padding, hash, hashed, sig)
}
}
impl RSAPrivateKey {
/// Generate a new RSA key pair of the given bit size using the passed in `rng`.
pub fn new<R: Rng>(rng: &mut R, bit_size: usize) -> Result<RSAPrivateKey> {
generate_multi_prime_key(rng, 2, bit_size)
}
/// Constructs an RSA key pair from the individual components.
pub fn from_components(
n: BigUint,
e: BigUint,
d: BigUint,
primes: Vec<BigUint>,
) -> RSAPrivateKey {
let mut k = RSAPrivateKey {
n,
e,
d,
primes,
precomputed: None,
};
k.precompute();
k
}
/// Performs some calculations to speed up private key operations.
pub fn precompute(&mut self) {
if self.precomputed.is_some() {
return;
}
let dp = &self.d % (&self.primes[0] - BigUint::one());
let dq = &self.d % (&self.primes[1] - BigUint::one());
let qinv = self.primes[1]
.clone()
.mod_inverse(&self.primes[0])
.expect("invalid prime");
let mut r: BigUint = &self.primes[0] * &self.primes[1];
let crt_values: Vec<CRTValue> = self
.primes
.iter()
.skip(2)
.map(|prime| {
let res = CRTValue {
exp: BigInt::from_biguint(Plus, &self.d % (prime - BigUint::one())),
r: BigInt::from_biguint(Plus, r.clone()),
coeff: BigInt::from_biguint(
Plus,
r.clone()
.mod_inverse(prime)
.expect("invalid coeff")
.to_biguint()
.unwrap(),
),
};
r *= prime;
res
})
.collect();
self.precomputed = Some(PrecomputedValues {
dp,
dq,
qinv,
crt_values,
});
}
/// Returns the private exponent of the key.
pub fn d(&self) -> &BigUint {
&self.d
}
/// Returns the prime factors.
pub fn primes(&self) -> &[BigUint] {
&self.primes
}
/// Performs basic sanity checks on the key.
/// Returns `Ok(())` if everything is good, otherwise an approriate error.
pub fn validate(&self) -> Result<()> {
check_public(self)?;
// Check that Πprimes == n.
let mut m = BigUint::one();
for prime in &self.primes {
// Any primes ≤ 1 will cause divide-by-zero panics later.
if *prime < BigUint::one() {
return Err(Error::InvalidPrime);
}
m *= prime;
}
if m != self.n {
return Err(Error::InvalidModulus);
}
// Check that de ≡ 1 mod p-1, for each prime.
// This implies that e is coprime to each p-1 as e has a multiplicative
// inverse. Therefore e is coprime to lcm(p-1,q-1,r-1,...) =
// exponent(/n). It also implies that a^de ≡ a mod p as a^(p-1) ≡ 1
// mod p. Thus a^de ≡ a mod n for all a coprime to n, as required.
let mut de = self.e.clone();
de *= self.d.clone();
for prime in &self.primes {
let congruence: BigUint = &de % (prime - BigUint::one());
if !congruence.is_one() {
return Err(Error::InvalidExponent);
}
}
Ok(())
}
/// Decrypt the given message.
pub fn decrypt(&self, padding: PaddingScheme, ciphertext: &[u8]) -> Result<Vec<u8>> {
match padding {
// need to pass any Rng as the type arg, so the type checker is happy, it is not actually used for anything
PaddingScheme::PKCS1v15 => pkcs1v15::decrypt::<ThreadRng>(None, self, ciphertext),
PaddingScheme::OAEP => unimplemented!("not yet implemented"),
_ => Err(Error::InvalidPaddingScheme),
}
}
/// Decrypt the given message.
/// Uses `rng` to blind the decryption process.
pub fn decrypt_blinded<R: Rng>(
&self,
rng: &mut R,
padding: PaddingScheme,
ciphertext: &[u8],
) -> Result<Vec<u8>> {
match padding {
PaddingScheme::PKCS1v15 => pkcs1v15::decrypt(Some(rng), self, ciphertext),
PaddingScheme::OAEP => unimplemented!("not yet implemented"),
_ => Err(Error::InvalidPaddingScheme),
}
}
/// Sign the given digest.
pub fn sign<H: Hash>(
&self,
padding: PaddingScheme,
hash: Option<&H>,
digest: &[u8],
) -> Result<Vec<u8>> {
match padding {
PaddingScheme::PKCS1v15 => pkcs1v15::sign::<ThreadRng, _>(None, self, hash, digest),
PaddingScheme::PSS => unimplemented!("not yet implemented"),
_ => Err(Error::InvalidPaddingScheme),
}
}
/// Sign the given digest.
/// Use `rng` for blinding.
pub fn sign_blinded<R: Rng, H: Hash>(
&self,
rng: &mut R,
padding: PaddingScheme,
hash: Option<&H>,
digest: &[u8],
) -> Result<Vec<u8>> {
match padding {
PaddingScheme::PKCS1v15 => pkcs1v15::sign(Some(rng), self, hash, digest),
PaddingScheme::PSS => unimplemented!("not yet implemented"),
_ => Err(Error::InvalidPaddingScheme),
}
}
}
/// Check that the public key is well formed and has an exponent within acceptable bounds.
#[inline]
pub fn check_public(public_key: &impl PublicKey) -> Result<()> {
if public_key.e() < &*MIN_PUB_EXPONENT {
return Err(Error::PublicExponentTooSmall);
}
if public_key.e() > &*MAX_PUB_EXPONENT {
return Err(Error::PublicExponentTooLarge);
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::internals;
use num_traits::{FromPrimitive, ToPrimitive};
use rand::{thread_rng, ThreadRng};
#[test]
fn test_from_into() {
let private_key = RSAPrivateKey {
n: BigUint::from_u64(100).unwrap(),
e: BigUint::from_u64(200).unwrap(),
d: BigUint::from_u64(123).unwrap(),
primes: vec![],
precomputed: None,
};
let public_key: RSAPublicKey = private_key.into();
assert_eq!(public_key.n().to_u64(), Some(100));
assert_eq!(public_key.e().to_u64(), Some(200));
}
fn test_key_basics(private_key: &RSAPrivateKey) {
private_key.validate().expect("invalid private key");
assert!(
private_key.d() < private_key.n(),
"private exponent too large"
);
let pub_key: RSAPublicKey = private_key.clone().into();
let m = BigUint::from_u64(42).expect("invalid 42");
let c = internals::encrypt(&pub_key, &m);
let m2 = internals::decrypt::<ThreadRng>(None, &private_key, &c)
.expect("unable to decrypt without blinding");
assert_eq!(m, m2);
let mut rng = thread_rng();
let m3 = internals::decrypt(Some(&mut rng), &private_key, &c)
.expect("unable to decrypt with blinding");
assert_eq!(m, m3);
}
macro_rules! key_generation {
($name:ident, $multi:expr, $size:expr) => {
#[test]
fn $name() {
let mut rng = thread_rng();
for _ in 0..10 {
let private_key = if $multi == 2 {
RSAPrivateKey::new(&mut rng, $size).expect("failed to generate key")
} else {
generate_multi_prime_key(&mut rng, $multi, $size).unwrap()
};
assert_eq!(private_key.n().bits(), $size);
test_key_basics(&private_key);
}
}
};
}
key_generation!(key_generation_128, 2, 128);
key_generation!(key_generation_1024, 2, 1024);
key_generation!(key_generation_multi_3_256, 3, 256);
key_generation!(key_generation_multi_4_64, 4, 64);
key_generation!(key_generation_multi_5_64, 5, 64);
key_generation!(key_generation_multi_8_576, 8, 576);
key_generation!(key_generation_multi_16_1024, 16, 1024);
#[test]
fn test_impossible_keys() {
// make sure not infinite loops are hit here.
let mut rng = thread_rng();
for i in 0..32 {
let _ = RSAPrivateKey::new(&mut rng, i).is_err();
let _ = generate_multi_prime_key(&mut rng, 3, i);
let _ = generate_multi_prime_key(&mut rng, 4, i);
let _ = generate_multi_prime_key(&mut rng, 5, i);
}
}
#[test]
fn test_negative_decryption_value() {
let private_key = RSAPrivateKey::from_components(
BigUint::from_bytes_le(&vec![
99, 192, 208, 179, 0, 220, 7, 29, 49, 151, 75, 107, 75, 73, 200, 180,
]),
BigUint::from_bytes_le(&vec![1, 0, 1]),
BigUint::from_bytes_le(&vec![
81, 163, 254, 144, 171, 159, 144, 42, 244, 133, 51, 249, 28, 12, 63, 65,
]),
vec![
BigUint::from_bytes_le(&vec![105, 101, 60, 173, 19, 153, 3, 192]),
BigUint::from_bytes_le(&vec![235, 65, 160, 134, 32, 136, 6, 241]),
],
);
for _ in 0..1000 {
test_key_basics(&private_key);
}
}
#[test]
#[cfg(feature = "serde1")]
fn test_serde() {
use rand::{SeedableRng, XorShiftRng};
use serde_test::{assert_tokens, Token};
let mut rng = XorShiftRng::from_seed([1; 16]);
let priv_key = RSAPrivateKey::new(&mut rng, 64).expect("failed to generate key");
let priv_tokens = [
Token::Struct {
name: "RSAPrivateKey",
len: 4,
},
Token::Str("n"),
Token::Seq { len: Some(2) },
Token::U32(1296829443),
Token::U32(2444363981),
Token::SeqEnd,
Token::Str("e"),
Token::Seq { len: Some(1) },
Token::U32(65537),
Token::SeqEnd,
Token::Str("d"),
Token::Seq { len: Some(2) },
Token::U32(298985985),
Token::U32(2349628418),
Token::SeqEnd,
Token::Str("primes"),
Token::Seq { len: Some(2) },
Token::Seq { len: Some(1) },
Token::U32(3238068481),
Token::SeqEnd,
Token::Seq { len: Some(1) },
Token::U32(3242199299),
Token::SeqEnd,
Token::SeqEnd,
Token::StructEnd,
];
assert_tokens(&priv_key, &priv_tokens);
let priv_tokens = [
Token::Struct {
name: "RSAPublicKey",
len: 2,
},
Token::Str("n"),
Token::Seq { len: Some(2) },
Token::U32(1296829443),
Token::U32(2444363981),
Token::SeqEnd,
Token::Str("e"),
Token::Seq { len: Some(1) },
Token::U32(65537),
Token::SeqEnd,
Token::StructEnd,
];
assert_tokens(&RSAPublicKey::from(priv_key), &priv_tokens);
}
}