Skip to content

Commit 645cd68

Browse files
fix(decryption): ensure values are positive
Fixes #2
1 parent d3e5d89 commit 645cd68

File tree

3 files changed

+63
-29
lines changed

3 files changed

+63
-29
lines changed

src/algorithms.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ pub fn generate_multi_prime_key<R: Rng>(
9696
continue 'next;
9797
}
9898

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

107107
Ok(RSAPrivateKey::from_components(
108108
n_final,
109-
BigUint::from_u64(EXP).unwrap(),
109+
BigUint::from_u64(EXP).expect("invalid static exponent"),
110110
d_final,
111111
primes,
112112
))

src/key.rs

Lines changed: 60 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ impl RSAPrivateKey {
206206
.clone()
207207
.mod_inverse(&self.primes[0])
208208
.map(|v| BigInt::from_biguint(Plus, v))
209-
.unwrap();
209+
.expect("invalid prime");
210210

211211
let mut r: BigUint = &self.primes[0] * &self.primes[1];
212212
let crt_values: Vec<CRTValue> = self
@@ -217,7 +217,10 @@ impl RSAPrivateKey {
217217
let res = CRTValue {
218218
exp: BigInt::from_biguint(Plus, &self.d % (prime - BigUint::one())),
219219
r: BigInt::from_biguint(Plus, r.clone()),
220-
coeff: BigInt::from_biguint(Plus, r.clone().mod_inverse(prime).unwrap()),
220+
coeff: BigInt::from_biguint(
221+
Plus,
222+
r.clone().mod_inverse(prime).expect("invalid coeff"),
223+
),
221224
};
222225
r *= prime;
223226

@@ -360,18 +363,16 @@ pub fn decrypt<R: Rng>(
360363
priv_key: &RSAPrivateKey,
361364
c: &BigUint,
362365
) -> Result<BigUint> {
363-
if c > priv_key.n() {
366+
if c >= priv_key.n() {
364367
return Err(Error::Decryption);
365368
}
366369

367370
if priv_key.n().is_zero() {
368371
return Err(Error::Decryption);
369372
}
370373

371-
let mut c = c.clone();
372374
let mut ir = None;
373-
374-
if let Some(ref mut rng) = rng {
375+
let c = if let Some(ref mut rng) = rng {
375376
// Blinding enabled. Blinding involves multiplying c by r^e.
376377
// Then the decryption operation performs (m^e * r^e)^d mod n
377378
// which equals mr mod n. The factor of r can then be removed
@@ -391,24 +392,32 @@ pub fn decrypt<R: Rng>(
391392

392393
let e = priv_key.e();
393394
let rpowe = r.modpow(&e, priv_key.n()); // N != 0
394-
c = (c * &rpowe) % priv_key.n();
395-
}
395+
(c * &rpowe) % priv_key.n()
396+
} else {
397+
c.clone()
398+
};
396399

397400
let m = match priv_key.precomputed {
398401
None => c.modpow(priv_key.d(), priv_key.n()),
399402
Some(ref precomputed) => {
400403
// We have the precalculated values needed for the CRT.
401-
let mut m = BigInt::from_biguint(Plus, c.modpow(&precomputed.dp, &priv_key.primes[0]));
402-
let mut m2 = BigInt::from_biguint(Plus, c.modpow(&precomputed.dq, &priv_key.primes[1]));
404+
405+
let p = &priv_key.primes[0];
406+
let q = &priv_key.primes[1];
407+
408+
let mut m = BigInt::from_biguint(Plus, c.modpow(&precomputed.dp, p));
409+
let mut m2 = BigInt::from_biguint(Plus, c.modpow(&precomputed.dq, q));
403410

404411
m -= &m2;
412+
405413
// clones make me sad :(
406414
let primes: Vec<_> = priv_key
407415
.primes
408416
.iter()
409417
.map(|v| BigInt::from_biguint(Plus, v.clone()))
410418
.collect();
411-
if m.is_negative() {
419+
420+
while m.is_negative() {
412421
m += &primes[0];
413422
}
414423
m *= &precomputed.qinv;
@@ -423,14 +432,14 @@ pub fn decrypt<R: Rng>(
423432
m2 -= &m;
424433
m2 *= &value.coeff;
425434
m2 %= prime;
426-
if m2.is_negative() {
435+
while m2.is_negative() {
427436
m2 += prime;
428437
}
429438
m2 *= &value.r;
430439
m += &m2;
431440
}
432441

433-
m.to_biguint().unwrap()
442+
m.to_biguint().expect("failed to decrypt")
434443
}
435444
};
436445

@@ -496,21 +505,23 @@ mod tests {
496505
assert_eq!(public_key.e().to_u64(), Some(200));
497506
}
498507

499-
fn test_key_basics(private_key: RSAPrivateKey) {
500-
private_key.validate().expect("failed to validate");
508+
fn test_key_basics(private_key: &RSAPrivateKey) {
509+
private_key.validate().expect("invalid private key");
501510

502511
assert!(
503512
private_key.d() < private_key.n(),
504513
"private exponent too large"
505514
);
506515

507516
let pub_key: RSAPublicKey = private_key.clone().into();
508-
let m = BigUint::from_u64(42).unwrap();
517+
let m = BigUint::from_u64(42).expect("invalid 42");
509518
let c = encrypt(&pub_key, &m);
510-
let m2 = decrypt::<ThreadRng>(None, &private_key, &c).unwrap();
519+
let m2 = decrypt::<ThreadRng>(None, &private_key, &c)
520+
.expect("unable to decrypt without blinding");
511521
assert_eq!(m, m2);
512522
let mut rng = thread_rng();
513-
let m3 = decrypt(Some(&mut rng), &private_key, &c).unwrap();
523+
let m3 =
524+
decrypt(Some(&mut rng), &private_key, &c).expect("unable to decrypt with blinding");
514525
assert_eq!(m, m3);
515526
}
516527

@@ -519,14 +530,17 @@ mod tests {
519530
#[test]
520531
fn $name() {
521532
let mut rng = thread_rng();
522-
let private_key = if $multi == 2 {
523-
RSAPrivateKey::new(&mut rng, $size).unwrap()
524-
} else {
525-
generate_multi_prime_key(&mut rng, $multi, $size).unwrap()
526-
};
527-
assert_eq!(private_key.n().bits(), $size);
528533

529-
test_key_basics(private_key);
534+
for _ in 0..10 {
535+
let private_key = if $multi == 2 {
536+
RSAPrivateKey::new(&mut rng, $size).expect("failed to generate key")
537+
} else {
538+
generate_multi_prime_key(&mut rng, $multi, $size).unwrap()
539+
};
540+
assert_eq!(private_key.n().bits(), $size);
541+
542+
test_key_basics(&private_key);
543+
}
530544
}
531545
};
532546
}
@@ -553,4 +567,25 @@ mod tests {
553567
let _ = generate_multi_prime_key(&mut rng, 5, i);
554568
}
555569
}
570+
571+
#[test]
572+
fn test_negative_decryption_value() {
573+
let private_key = RSAPrivateKey::from_components(
574+
BigUint::from_bytes_le(&vec![
575+
99, 192, 208, 179, 0, 220, 7, 29, 49, 151, 75, 107, 75, 73, 200, 180,
576+
]),
577+
BigUint::from_bytes_le(&vec![1, 0, 1]),
578+
BigUint::from_bytes_le(&vec![
579+
81, 163, 254, 144, 171, 159, 144, 42, 244, 133, 51, 249, 28, 12, 63, 65,
580+
]),
581+
vec![
582+
BigUint::from_bytes_le(&vec![105, 101, 60, 173, 19, 153, 3, 192]),
583+
BigUint::from_bytes_le(&vec![235, 65, 160, 134, 32, 136, 6, 241]),
584+
],
585+
);
586+
587+
for _ in 0..1000 {
588+
test_key_basics(&private_key);
589+
}
590+
}
556591
}

src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
#![doc(html_logo_url =
2-
"https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")]
1+
#![doc(html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")]
32
extern crate num_bigint_dig as num_bigint;
43
extern crate num_integer;
54
extern crate num_traits;

0 commit comments

Comments
 (0)