Skip to content

Commit

Permalink
Merge pull request #4 from RustCrypto/test
Browse files Browse the repository at this point in the history
fix(decryption): ensure values are positive
  • Loading branch information
dignifiedquire authored Dec 5, 2018
2 parents d3e5d89 + 645cd68 commit 90975f3
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 29 deletions.
4 changes: 2 additions & 2 deletions src/algorithms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ pub fn generate_multi_prime_key<R: Rng>(
continue 'next;
}

let exp = BigUint::from_u64(EXP).unwrap();
let exp = BigUint::from_u64(EXP).expect("invalid static exponent");
if let Some(d) = exp.mod_inverse(totient) {
n_final = n;
d_final = d;
Expand All @@ -106,7 +106,7 @@ pub fn generate_multi_prime_key<R: Rng>(

Ok(RSAPrivateKey::from_components(
n_final,
BigUint::from_u64(EXP).unwrap(),
BigUint::from_u64(EXP).expect("invalid static exponent"),
d_final,
primes,
))
Expand Down
85 changes: 60 additions & 25 deletions src/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ impl RSAPrivateKey {
.clone()
.mod_inverse(&self.primes[0])
.map(|v| BigInt::from_biguint(Plus, v))
.unwrap();
.expect("invalid prime");

let mut r: BigUint = &self.primes[0] * &self.primes[1];
let crt_values: Vec<CRTValue> = self
Expand All @@ -217,7 +217,10 @@ impl RSAPrivateKey {
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).unwrap()),
coeff: BigInt::from_biguint(
Plus,
r.clone().mod_inverse(prime).expect("invalid coeff"),
),
};
r *= prime;

Expand Down Expand Up @@ -360,18 +363,16 @@ pub fn decrypt<R: Rng>(
priv_key: &RSAPrivateKey,
c: &BigUint,
) -> Result<BigUint> {
if c > priv_key.n() {
if c >= priv_key.n() {
return Err(Error::Decryption);
}

if priv_key.n().is_zero() {
return Err(Error::Decryption);
}

let mut c = c.clone();
let mut ir = None;

if let Some(ref mut rng) = rng {
let c = if let Some(ref mut rng) = rng {
// Blinding enabled. Blinding involves multiplying c by r^e.
// Then the decryption operation performs (m^e * r^e)^d mod n
// which equals mr mod n. The factor of r can then be removed
Expand All @@ -391,24 +392,32 @@ pub fn decrypt<R: Rng>(

let e = priv_key.e();
let rpowe = r.modpow(&e, priv_key.n()); // N != 0
c = (c * &rpowe) % priv_key.n();
}
(c * &rpowe) % priv_key.n()
} else {
c.clone()
};

let m = match priv_key.precomputed {
None => c.modpow(priv_key.d(), priv_key.n()),
Some(ref precomputed) => {
// We have the precalculated values needed for the CRT.
let mut m = BigInt::from_biguint(Plus, c.modpow(&precomputed.dp, &priv_key.primes[0]));
let mut m2 = BigInt::from_biguint(Plus, c.modpow(&precomputed.dq, &priv_key.primes[1]));

let p = &priv_key.primes[0];
let q = &priv_key.primes[1];

let mut m = BigInt::from_biguint(Plus, c.modpow(&precomputed.dp, p));
let mut m2 = BigInt::from_biguint(Plus, c.modpow(&precomputed.dq, q));

m -= &m2;

// clones make me sad :(
let primes: Vec<_> = priv_key
.primes
.iter()
.map(|v| BigInt::from_biguint(Plus, v.clone()))
.collect();
if m.is_negative() {

while m.is_negative() {
m += &primes[0];
}
m *= &precomputed.qinv;
Expand All @@ -423,14 +432,14 @@ pub fn decrypt<R: Rng>(
m2 -= &m;
m2 *= &value.coeff;
m2 %= prime;
if m2.is_negative() {
while m2.is_negative() {
m2 += prime;
}
m2 *= &value.r;
m += &m2;
}

m.to_biguint().unwrap()
m.to_biguint().expect("failed to decrypt")
}
};

Expand Down Expand Up @@ -496,21 +505,23 @@ mod tests {
assert_eq!(public_key.e().to_u64(), Some(200));
}

fn test_key_basics(private_key: RSAPrivateKey) {
private_key.validate().expect("failed to validate");
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).unwrap();
let m = BigUint::from_u64(42).expect("invalid 42");
let c = encrypt(&pub_key, &m);
let m2 = decrypt::<ThreadRng>(None, &private_key, &c).unwrap();
let m2 = decrypt::<ThreadRng>(None, &private_key, &c)
.expect("unable to decrypt without blinding");
assert_eq!(m, m2);
let mut rng = thread_rng();
let m3 = decrypt(Some(&mut rng), &private_key, &c).unwrap();
let m3 =
decrypt(Some(&mut rng), &private_key, &c).expect("unable to decrypt with blinding");
assert_eq!(m, m3);
}

Expand All @@ -519,14 +530,17 @@ mod tests {
#[test]
fn $name() {
let mut rng = thread_rng();
let private_key = if $multi == 2 {
RSAPrivateKey::new(&mut rng, $size).unwrap()
} else {
generate_multi_prime_key(&mut rng, $multi, $size).unwrap()
};
assert_eq!(private_key.n().bits(), $size);

test_key_basics(private_key);
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);
}
}
};
}
Expand All @@ -553,4 +567,25 @@ mod tests {
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);
}
}
}
3 changes: 1 addition & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#![doc(html_logo_url =
"https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")]
#![doc(html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")]
extern crate num_bigint_dig as num_bigint;
extern crate num_integer;
extern crate num_traits;
Expand Down

0 comments on commit 90975f3

Please sign in to comment.