Skip to content

Commit f4131c5

Browse files
fix blinding and fold in new impl
1 parent 98a86a2 commit f4131c5

File tree

4 files changed

+68
-198
lines changed

4 files changed

+68
-198
lines changed

Cargo.lock

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,6 @@ rustdoc-args = ["--cfg", "docsrs"]
6565

6666
[profile.dev]
6767
opt-level = 2
68+
69+
[patch.crates-io]
70+
crypto-bigint = { git = "https://github.com/RustCrypto/crypto-bigint", branch = "master" }

src/algorithms/rsa.rs

Lines changed: 63 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
//! Generic RSA implementation
22
3-
use alloc::borrow::Cow;
43
use alloc::vec::Vec;
54
use crypto_bigint::modular::BoxedResidueParams;
6-
use crypto_bigint::{BoxedUint, NonZero};
7-
use num_bigint::{BigInt, BigUint, IntoBigInt, IntoBigUint, ModInverse, RandBigInt, ToBigInt};
5+
use crypto_bigint::{BoxedUint, RandomMod};
6+
use num_bigint::{BigUint, IntoBigInt, IntoBigUint, ModInverse, ToBigInt};
87
use num_integer::{sqrt, Integer};
98
use num_traits::{FromPrimitive, One, Pow, Signed, Zero as _};
109
use rand_core::CryptoRngCore;
@@ -14,7 +13,7 @@ use zeroize::{Zeroize, Zeroizing};
1413
use crate::errors::{Error, Result};
1514
use crate::key::{reduce, to_biguint, to_uint};
1615
use crate::traits::keys::{PrivateKeyPartsNew, PublicKeyPartsNew};
17-
use crate::traits::{PrivateKeyParts, PublicKeyParts};
16+
use crate::traits::PublicKeyParts;
1817

1918
/// ⚠️ Raw RSA encryption of m with the public key. No padding is performed.
2019
///
@@ -38,25 +37,35 @@ pub fn rsa_encrypt<K: PublicKeyParts>(key: &K, m: &BigUint) -> Result<BigUint> {
3837
#[inline]
3938
pub fn rsa_decrypt<R: CryptoRngCore + ?Sized>(
4039
mut rng: Option<&mut R>,
41-
priv_key: &impl PrivateKeyParts,
42-
c: &BigUint,
40+
priv_key: &impl PrivateKeyPartsNew,
41+
c_orig: &BigUint,
4342
) -> Result<BigUint> {
44-
if c >= &priv_key.n() {
43+
// convert to crypto bigint
44+
let c = to_uint(c_orig.clone());
45+
let n = priv_key.n();
46+
let d = priv_key.d();
47+
48+
if c >= **n {
4549
return Err(Error::Decryption);
4650
}
4751

48-
if priv_key.n().is_zero() {
52+
// TODO: is this fine?
53+
if n.is_zero().into() {
4954
return Err(Error::Decryption);
5055
}
5156

5257
let mut ir = None;
5358

59+
let n_params = priv_key
60+
.residue_params()
61+
.cloned()
62+
.unwrap_or_else(|| BoxedResidueParams::new(n.clone().get()).unwrap());
5463
let c = if let Some(ref mut rng) = rng {
55-
let (blinded, unblinder) = blind(rng, priv_key, c);
64+
let (blinded, unblinder) = blind(rng, priv_key, &c, &n_params);
5665
ir = Some(unblinder);
57-
Cow::Owned(blinded)
66+
blinded
5867
} else {
59-
Cow::Borrowed(c)
68+
c
6069
};
6170

6271
let dp = priv_key.dp();
@@ -68,19 +77,21 @@ pub fn rsa_decrypt<R: CryptoRngCore + ?Sized>(
6877
(Some(dp), Some(dq), Some(qinv), Some(crt_values)) => {
6978
// We have the precalculated values needed for the CRT.
7079

71-
let p = &priv_key.primes()[0];
72-
let q = &priv_key.primes()[1];
80+
let dp = to_biguint(dp);
81+
let dq = to_biguint(dq);
82+
let qinv = to_biguint(qinv).to_bigint().unwrap();
83+
let p = to_biguint(&priv_key.primes()[0]);
84+
let q = to_biguint(&priv_key.primes()[1]);
7385

74-
let mut m = c.modpow(&dp, p).into_bigint().unwrap();
75-
let mut m2 = c.modpow(&dq, q).into_bigint().unwrap();
86+
let mut m = c_orig.modpow(&dp, &p).into_bigint().unwrap();
87+
let mut m2 = c_orig.modpow(&dq, &q).into_bigint().unwrap();
7688

7789
m -= &m2;
7890

7991
let mut primes: Vec<_> = priv_key
8092
.primes()
8193
.iter()
82-
.map(ToBigInt::to_bigint)
83-
.map(Option::unwrap)
94+
.map(|p| to_biguint(p).to_bigint().unwrap())
8495
.collect();
8596

8697
while m.is_negative() {
@@ -91,17 +102,17 @@ pub fn rsa_decrypt<R: CryptoRngCore + ?Sized>(
91102
m *= &primes[1];
92103
m += &m2;
93104

94-
let mut c = c.into_owned().into_bigint().unwrap();
105+
let mut c = c_orig.to_bigint().unwrap();
95106
for (i, value) in crt_values.iter().enumerate() {
96107
let prime = &primes[2 + i];
97-
m2 = c.modpow(&value.exp, prime);
108+
m2 = c.modpow(&to_biguint(&value.exp).to_bigint().unwrap(), prime);
98109
m2 -= &m;
99-
m2 *= &value.coeff;
110+
m2 *= &to_biguint(&value.coeff).to_bigint().unwrap();
100111
m2 %= prime;
101112
while m2.is_negative() {
102113
m2 += prime;
103114
}
104-
m2 *= &value.r;
115+
m2 *= &to_biguint(&value.r).to_bigint().unwrap();
105116
m += &m2;
106117
}
107118

@@ -113,17 +124,21 @@ pub fn rsa_decrypt<R: CryptoRngCore + ?Sized>(
113124
c.zeroize();
114125
m2.zeroize();
115126

116-
m.into_biguint().expect("failed to decrypt")
127+
to_uint(m.into_biguint().expect("failed to decrypt"))
128+
}
129+
_ => {
130+
let c = reduce(&c, n_params);
131+
c.pow(&d).retrieve()
117132
}
118-
_ => c.modpow(&priv_key.d(), &priv_key.n()),
119133
};
120134

121135
match ir {
122136
Some(ref ir) => {
123137
// unblind
124-
Ok(unblind(priv_key, &m, ir))
138+
let res = to_biguint(&unblind(priv_key, &m, ir));
139+
Ok(res)
125140
}
126-
None => Ok(m),
141+
None => Ok(to_biguint(&m)),
127142
}
128143
}
129144

@@ -138,29 +153,11 @@ pub fn rsa_decrypt<R: CryptoRngCore + ?Sized>(
138153
/// or signature scheme. See the [module-level documentation][crate::hazmat] for more information.
139154
#[inline]
140155
pub fn rsa_decrypt_and_check<R: CryptoRngCore + ?Sized>(
141-
priv_key: &impl PrivateKeyParts,
142-
rng: Option<&mut R>,
143-
c: &BigUint,
144-
) -> Result<BigUint> {
145-
let m = rsa_decrypt(rng, priv_key, c)?;
146-
147-
// In order to defend against errors in the CRT computation, m^e is
148-
// calculated, which should match the original ciphertext.
149-
let check = rsa_encrypt(priv_key, &m)?;
150-
151-
if c != &check {
152-
return Err(Error::Internal);
153-
}
154-
155-
Ok(m)
156-
}
157-
158-
pub fn rsa_decrypt_and_check_new<R: CryptoRngCore + ?Sized>(
159156
priv_key: &impl PrivateKeyPartsNew,
160157
rng: Option<&mut R>,
161158
c: &BigUint,
162159
) -> Result<BigUint> {
163-
let m = rsa_decrypt_new(rng, priv_key, c)?;
160+
let m = rsa_decrypt(rng, priv_key, c)?;
164161

165162
// In order to defend against errors in the CRT computation, m^e is
166163
// calculated, which should match the original ciphertext.
@@ -174,38 +171,40 @@ pub fn rsa_decrypt_and_check_new<R: CryptoRngCore + ?Sized>(
174171
}
175172

176173
/// Returns the blinded c, along with the unblinding factor.
177-
fn blind<R: CryptoRngCore, K: PublicKeyParts>(
174+
fn blind<R: CryptoRngCore, K: PublicKeyPartsNew>(
178175
rng: &mut R,
179176
key: &K,
180-
c: &BigUint,
181-
) -> (BigUint, BigUint) {
177+
c: &BoxedUint,
178+
n_params: &BoxedResidueParams,
179+
) -> (BoxedUint, BoxedUint) {
182180
// Blinding involves multiplying c by r^e.
183181
// Then the decryption operation performs (m^e * r^e)^d mod n
184182
// which equals mr mod n. The factor of r can then be removed
185183
// by multiplying by the multiplicative inverse of r.
186184

187-
let mut r: BigUint;
188-
let mut ir: Option<BigInt>;
185+
let mut r: BoxedUint;
186+
let mut ir: CtOption<BoxedUint>;
189187
let unblinder;
190188
loop {
191-
r = rng.gen_biguint_below(&key.n());
192-
if r.is_zero() {
193-
r = BigUint::one();
189+
// TODO: use constant time gen
190+
r = BoxedUint::random_mod(rng, key.n());
191+
// TODO: correct mapping
192+
if r.is_zero().into() {
193+
r = BoxedUint::one();
194194
}
195-
ir = r.clone().mod_inverse(key.n());
196-
if let Some(ir) = ir {
197-
if let Some(ub) = ir.into_biguint() {
198-
unblinder = ub;
199-
break;
200-
}
195+
ir = r.inv_mod(key.n());
196+
197+
// TODO: constant time?
198+
if let Some(ir) = ir.into() {
199+
unblinder = ir;
200+
break;
201201
}
202202
}
203203

204204
let c = {
205-
let mut rpowe = r.modpow(&key.e(), &key.n()); // N != 0
206-
let mut c = c * &rpowe;
207-
c %= key.n();
208-
205+
let r = reduce(&r, n_params.clone());
206+
let mut rpowe = r.pow(key.e()).retrieve();
207+
let c = c.mul_mod(&rpowe, key.n());
209208
rpowe.zeroize();
210209

211210
c
@@ -215,8 +214,8 @@ fn blind<R: CryptoRngCore, K: PublicKeyParts>(
215214
}
216215

217216
/// Given an m and and unblinding factor, unblind the m.
218-
fn unblind(key: &impl PublicKeyParts, m: &BigUint, unblinder: &BigUint) -> BigUint {
219-
(m * unblinder) % key.n()
217+
fn unblind(key: &impl PublicKeyPartsNew, m: &BoxedUint, unblinder: &BoxedUint) -> BoxedUint {
218+
m.mul_mod(unblinder, key.n())
220219
}
221220

222221
/// The following (deterministic) algorithm also recovers the prime factors `p` and `q` of a modulus `n`, given the
@@ -326,99 +325,6 @@ pub(crate) fn compute_private_exponent_carmicheal(
326325
}
327326
}
328327

329-
fn blind_new<R: CryptoRngCore, K: PublicKeyPartsNew>(
330-
rng: &mut R,
331-
key: &K,
332-
c: &BoxedUint,
333-
n_params: &BoxedResidueParams,
334-
) -> (BoxedUint, BoxedUint) {
335-
let mut r: BoxedUint;
336-
let mut ir: CtOption<BoxedUint>;
337-
let unblinder;
338-
loop {
339-
// TODO: use constant time gen
340-
r = to_uint(rng.gen_biguint_below(&to_biguint(&key.n())));
341-
// TODO: correct mapping
342-
if r.is_zero().into() {
343-
r = BoxedUint::one();
344-
}
345-
ir = r.inv_mod(key.n());
346-
347-
// TODO: constant time?
348-
if let Some(ir) = ir.into() {
349-
unblinder = ir;
350-
break;
351-
}
352-
}
353-
354-
let c = {
355-
let r = reduce(&r, n_params.clone());
356-
let mut rpowe = r.pow(key.e()).retrieve();
357-
358-
let c = c.wrapping_mul(&rpowe);
359-
let c = c.rem_vartime(key.n());
360-
361-
rpowe.zeroize();
362-
363-
c
364-
};
365-
366-
(c, unblinder)
367-
}
368-
369-
fn unblind_new(key: &impl PublicKeyPartsNew, m: &BoxedUint, unblinder: &BoxedUint) -> BoxedUint {
370-
let a = m.wrapping_mul(unblinder);
371-
a.rem_vartime(key.n())
372-
}
373-
374-
pub fn rsa_decrypt_new<R: CryptoRngCore + ?Sized>(
375-
mut rng: Option<&mut R>,
376-
priv_key: &impl PrivateKeyPartsNew,
377-
c: &BigUint,
378-
) -> Result<BigUint> {
379-
// convert to crypto bigint
380-
let c = to_uint(c.clone());
381-
let n = priv_key.n();
382-
let d = priv_key.d();
383-
384-
if c >= **n {
385-
return Err(Error::Decryption);
386-
}
387-
388-
// TODO: is this fine?
389-
if n.is_zero().into() {
390-
return Err(Error::Decryption);
391-
}
392-
393-
let mut ir = None;
394-
395-
let n_params = priv_key
396-
.residue_params()
397-
.cloned()
398-
.unwrap_or_else(|| BoxedResidueParams::new(n.clone().get()).unwrap());
399-
400-
let c = if let Some(ref mut rng) = rng {
401-
let (blinded, unblinder) = blind_new(rng, priv_key, &c, &n_params);
402-
ir = Some(unblinder);
403-
blinded
404-
} else {
405-
c
406-
};
407-
408-
// TODO: fast path with precalculated values;
409-
let c = reduce(&c, n_params);
410-
let m = c.pow(&d).retrieve();
411-
412-
match ir {
413-
Some(ref ir) => {
414-
// unblind
415-
let m = unblind_new(priv_key, &m, ir);
416-
Ok(to_biguint(&m))
417-
}
418-
None => Ok(to_biguint(&m)),
419-
}
420-
}
421-
422328
#[cfg(test)]
423329
mod tests {
424330
use num_traits::FromPrimitive;

0 commit comments

Comments
 (0)