Skip to content

Commit 2dafa35

Browse files
implement basic widening strategy
1 parent f4131c5 commit 2dafa35

File tree

2 files changed

+112
-48
lines changed

2 files changed

+112
-48
lines changed

src/algorithms/rsa.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Generic RSA implementation
22
33
use alloc::vec::Vec;
4-
use crypto_bigint::modular::BoxedResidueParams;
4+
use crypto_bigint::modular::{BoxedResidue, BoxedResidueParams};
55
use crypto_bigint::{BoxedUint, RandomMod};
66
use num_bigint::{BigUint, IntoBigInt, IntoBigUint, ModInverse, ToBigInt};
77
use num_integer::{sqrt, Integer};
@@ -11,7 +11,7 @@ use subtle::CtOption;
1111
use zeroize::{Zeroize, Zeroizing};
1212

1313
use crate::errors::{Error, Result};
14-
use crate::key::{reduce, to_biguint, to_uint};
14+
use crate::key::{reduce, to_biguint, to_uint_exact};
1515
use crate::traits::keys::{PrivateKeyPartsNew, PublicKeyPartsNew};
1616
use crate::traits::PublicKeyParts;
1717

@@ -40,11 +40,13 @@ pub fn rsa_decrypt<R: CryptoRngCore + ?Sized>(
4040
priv_key: &impl PrivateKeyPartsNew,
4141
c_orig: &BigUint,
4242
) -> Result<BigUint> {
43-
// convert to crypto bigint
44-
let c = to_uint(c_orig.clone());
4543
let n = priv_key.n();
44+
let nbits = n.bits_precision();
45+
let c = to_uint_exact(c_orig.clone(), nbits);
4646
let d = priv_key.d();
4747

48+
std::dbg!(nbits, d.bits_precision(), c.bits_precision());
49+
4850
if c >= **n {
4951
return Err(Error::Decryption);
5052
}
@@ -124,18 +126,18 @@ pub fn rsa_decrypt<R: CryptoRngCore + ?Sized>(
124126
c.zeroize();
125127
m2.zeroize();
126128

127-
to_uint(m.into_biguint().expect("failed to decrypt"))
129+
to_uint_exact(m.into_biguint().expect("failed to decrypt"), nbits)
128130
}
129131
_ => {
130-
let c = reduce(&c, n_params);
132+
let c = reduce(&c, n_params.clone());
131133
c.pow(&d).retrieve()
132134
}
133135
};
134136

135137
match ir {
136138
Some(ref ir) => {
137139
// unblind
138-
let res = to_biguint(&unblind(priv_key, &m, ir));
140+
let res = to_biguint(&unblind(&m, ir, n_params));
139141
Ok(res)
140142
}
141143
None => Ok(to_biguint(&m)),
@@ -204,7 +206,7 @@ fn blind<R: CryptoRngCore, K: PublicKeyPartsNew>(
204206
let c = {
205207
let r = reduce(&r, n_params.clone());
206208
let mut rpowe = r.pow(key.e()).retrieve();
207-
let c = c.mul_mod(&rpowe, key.n());
209+
let c = mul_mod_params(c, &rpowe, n_params.clone());
208210
rpowe.zeroize();
209211

210212
c
@@ -213,9 +215,17 @@ fn blind<R: CryptoRngCore, K: PublicKeyPartsNew>(
213215
(c, unblinder)
214216
}
215217

218+
/// Computes `lhs.mul_mod(rhs, n)` with precomputed `n_param`.
219+
fn mul_mod_params(lhs: &BoxedUint, rhs: &BoxedUint, n_params: BoxedResidueParams) -> BoxedUint {
220+
// TODO: nicer api in crypto-bigint?
221+
let lhs = BoxedResidue::new(lhs, n_params.clone());
222+
let rhs = BoxedResidue::new(rhs, n_params);
223+
(lhs * rhs).retrieve()
224+
}
225+
216226
/// Given an m and and unblinding factor, unblind the m.
217-
fn unblind(key: &impl PublicKeyPartsNew, m: &BoxedUint, unblinder: &BoxedUint) -> BoxedUint {
218-
m.mul_mod(unblinder, key.n())
227+
fn unblind(m: &BoxedUint, unblinder: &BoxedUint, n_params: BoxedResidueParams) -> BoxedUint {
228+
mul_mod_params(m, unblinder, n_params)
219229
}
220230

221231
/// The following (deterministic) algorithm also recovers the prime factors `p` and `q` of a modulus `n`, given the

src/key.rs

Lines changed: 92 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,13 @@ impl RsaPublicKey {
200200

201201
/// Create a new public key from its components.
202202
pub fn new_with_max_size(n: BigUint, e: BigUint, max_size: usize) -> Result<Self> {
203-
let k = Self {
204-
n: NonZero::new(to_uint(n)).unwrap(),
205-
e: to_uint(e),
206-
};
207-
check_public_with_max_size(&k, max_size)?;
203+
check_public_with_max_size(&n, &e, max_size)?;
204+
205+
let n = NonZero::new(to_uint(n)).unwrap();
206+
// widen to 64bit
207+
let e = to_uint_exact(e, 64);
208+
let k = Self { n, e };
209+
208210
Ok(k)
209211
}
210212

@@ -215,10 +217,30 @@ impl RsaPublicKey {
215217
/// Most applications should use [`RsaPublicKey::new`] or
216218
/// [`RsaPublicKey::new_with_max_size`] instead.
217219
pub fn new_unchecked(n: BigUint, e: BigUint) -> Self {
218-
Self {
219-
n: NonZero::new(to_uint(n)).unwrap(),
220-
e: to_uint(e),
221-
}
220+
// TODO: widen?
221+
let n = NonZero::new(to_uint(n)).unwrap();
222+
let e = to_uint_exact(e, 64);
223+
Self { n, e }
224+
}
225+
}
226+
227+
fn needed_bits(n: &BigUint) -> usize {
228+
// widen to the max size bits
229+
let n_bits = n.bits();
230+
231+
// TODO: better algorithm/more sizes
232+
if n_bits <= 512 {
233+
512
234+
} else if n_bits <= 1024 {
235+
1024
236+
} else if n_bits <= 2048 {
237+
2048
238+
} else if n_bits <= 4096 {
239+
4096
240+
} else if n_bits <= 8192 {
241+
8192
242+
} else {
243+
16384
222244
}
223245
}
224246

@@ -274,8 +296,16 @@ impl RsaPrivateKey {
274296
d: BigUint,
275297
primes: Vec<BigUint>,
276298
) -> Result<RsaPrivateKey> {
299+
let n_c = NonZero::new(to_uint(n.clone())).unwrap();
300+
let nbits = n_c.bits_precision();
301+
302+
std::dbg!(nbits);
303+
277304
let mut should_validate = false;
278-
let mut primes: Vec<_> = primes.into_iter().map(to_uint).collect();
305+
let mut primes: Vec<_> = primes
306+
.into_iter()
307+
.map(|p| to_uint_exact(p, nbits))
308+
.collect();
279309

280310
if primes.len() < 2 {
281311
if !primes.is_empty() {
@@ -284,17 +314,15 @@ impl RsaPrivateKey {
284314
// Recover `p` and `q` from `d`.
285315
// See method in Appendix C.2: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br2.pdf
286316
let (p, q) = recover_primes(&n, &e, &d)?;
287-
primes.push(to_uint(p));
288-
primes.push(to_uint(q));
317+
primes.push(to_uint_exact(p, nbits));
318+
primes.push(to_uint_exact(q, nbits));
289319
should_validate = true;
290320
}
291321

322+
let e = to_uint_exact(e, 64);
292323
let mut k = RsaPrivateKey {
293-
pubkey_components: RsaPublicKey {
294-
n: NonZero::new(to_uint(n)).unwrap(),
295-
e: to_uint(e),
296-
},
297-
d: to_uint(d),
324+
pubkey_components: RsaPublicKey { n: n_c, e },
325+
d: to_uint_exact(d, nbits),
298326
primes,
299327
precomputed: None,
300328
};
@@ -363,6 +391,10 @@ impl RsaPrivateKey {
363391
if self.precomputed.is_some() {
364392
return Ok(());
365393
}
394+
395+
// already widened to what we need
396+
let nbits = self.pubkey_components.n.bits_precision();
397+
366398
let d = to_biguint(&self.d);
367399
let dp = &d % (&to_biguint(&self.primes[0]) - BigUint::one());
368400
let dq = &d % (&to_biguint(&self.primes[1]) - BigUint::one());
@@ -378,14 +410,15 @@ impl RsaPrivateKey {
378410
for prime in &self.primes[2..] {
379411
let prime = to_biguint(prime);
380412
let res = CrtValueNew {
381-
exp: to_uint(&d % (&prime - BigUint::one())),
382-
r: to_uint(r.clone()),
383-
coeff: to_uint(
413+
exp: to_uint_exact(&d % (&prime - BigUint::one()), nbits),
414+
r: to_uint_exact(r.clone(), nbits),
415+
coeff: to_uint_exact(
384416
r.clone()
385417
.mod_inverse(&prime)
386418
.ok_or(Error::InvalidCoefficient)?
387419
.to_biguint()
388420
.unwrap(),
421+
nbits,
389422
),
390423
};
391424
r *= prime;
@@ -400,8 +433,8 @@ impl RsaPrivateKey {
400433
BoxedResidueParams::new(self.pubkey_components.n.clone().get()).unwrap();
401434

402435
self.precomputed = Some(PrecomputedValues {
403-
dp: to_uint(dp),
404-
dq: to_uint(dq),
436+
dp: to_uint_exact(dp, nbits),
437+
dq: to_uint_exact(dq, nbits),
405438
qinv,
406439
crt_values,
407440
residue_params,
@@ -539,34 +572,31 @@ impl PrivateKeyPartsNew for RsaPrivateKey {
539572
/// Check that the public key is well formed and has an exponent within acceptable bounds.
540573
#[inline]
541574
pub fn check_public(public_key: &impl PublicKeyParts) -> Result<()> {
542-
check_public_with_max_size(public_key, RsaPublicKey::MAX_SIZE)
575+
check_public_with_max_size(&public_key.n(), &public_key.e(), RsaPublicKey::MAX_SIZE)
543576
}
544577

545578
/// Check that the public key is well formed and has an exponent within acceptable bounds.
546579
#[inline]
547-
fn check_public_with_max_size(public_key: &impl PublicKeyParts, max_size: usize) -> Result<()> {
548-
if public_key.n().bits() > max_size {
580+
fn check_public_with_max_size(n: &BigUint, e: &BigUint, max_size: usize) -> Result<()> {
581+
if n.bits() > max_size {
549582
return Err(Error::ModulusTooLarge);
550583
}
551584

552-
let e = public_key
553-
.e()
554-
.to_u64()
555-
.ok_or(Error::PublicExponentTooLarge)?;
585+
let eu64 = e.to_u64().ok_or(Error::PublicExponentTooLarge)?;
556586

557-
if public_key.e() >= public_key.n() || public_key.n().is_even() {
587+
if e >= n || n.is_even() {
558588
return Err(Error::InvalidModulus);
559589
}
560590

561-
if public_key.e().is_even() {
591+
if e.is_even() {
562592
return Err(Error::InvalidExponent);
563593
}
564594

565-
if e < RsaPublicKey::MIN_PUB_EXPONENT {
595+
if eu64 < RsaPublicKey::MIN_PUB_EXPONENT {
566596
return Err(Error::PublicExponentTooSmall);
567597
}
568598

569-
if e > RsaPublicKey::MAX_PUB_EXPONENT {
599+
if eu64 > RsaPublicKey::MAX_PUB_EXPONENT {
570600
return Err(Error::PublicExponentTooLarge);
571601
}
572602

@@ -577,12 +607,35 @@ pub(crate) fn to_biguint(uint: &BoxedUint) -> BigUint {
577607
BigUint::from_bytes_be(&uint.to_be_bytes())
578608
}
579609

610+
pub(crate) fn to_uint_exact(big_uint: BigUint, nbits: usize) -> BoxedUint {
611+
let bytes = big_uint.to_bytes_be();
612+
let pad_count = Limb::BYTES - (bytes.len() % Limb::BYTES);
613+
let mut padded_bytes = vec![0u8; pad_count];
614+
padded_bytes.extend_from_slice(&bytes);
615+
616+
let res = BoxedUint::from_be_slice(&padded_bytes, padded_bytes.len() * 8).unwrap();
617+
618+
match res.bits_precision().cmp(&nbits) {
619+
Ordering::Equal => res,
620+
Ordering::Greater => panic!("too large: {} > {}", res.bits_precision(), nbits),
621+
Ordering::Less => res.widen(nbits),
622+
}
623+
}
624+
580625
pub(crate) fn to_uint(big_uint: BigUint) -> BoxedUint {
626+
let nbits = needed_bits(&big_uint);
627+
581628
let bytes = big_uint.to_bytes_be();
582629
let pad_count = Limb::BYTES - (bytes.len() % Limb::BYTES);
583630
let mut padded_bytes = vec![0u8; pad_count];
584631
padded_bytes.extend_from_slice(&bytes);
585-
BoxedUint::from_be_slice(&padded_bytes, padded_bytes.len() * 8).unwrap()
632+
633+
let res = BoxedUint::from_be_slice(&padded_bytes, padded_bytes.len() * 8).unwrap();
634+
635+
if res.bits() < nbits {
636+
return res.widen(nbits);
637+
}
638+
res
586639
}
587640

588641
pub(crate) fn reduce(n: &BoxedUint, p: BoxedResidueParams) -> BoxedResidue {
@@ -614,10 +667,10 @@ mod tests {
614667
fn test_from_into() {
615668
let private_key = RsaPrivateKey {
616669
pubkey_components: RsaPublicKey {
617-
n: NonZero::new(to_uint(BigUint::from_u64(100).unwrap())).unwrap(),
618-
e: to_uint(BigUint::from_u64(200).unwrap()),
670+
n: NonZero::new(to_uint(BigUint::from_u64(100).unwrap()).widen(64)).unwrap(),
671+
e: to_uint(BigUint::from_u64(200).unwrap()).widen(64),
619672
},
620-
d: to_uint(BigUint::from_u64(123).unwrap()),
673+
d: to_uint(BigUint::from_u64(123).unwrap()).widen(64),
621674
primes: vec![],
622675
precomputed: None,
623676
};
@@ -654,7 +707,8 @@ mod tests {
654707
let mut rng = ChaCha8Rng::from_seed([42; 32]);
655708
let exp = BigUint::from_u64(RsaPrivateKey::EXP).expect("invalid static exponent");
656709

657-
for _ in 0..10 {
710+
for i in 0..10 {
711+
std::dbg!(i, $size);
658712
let components =
659713
generate_multi_prime_key_with_exp(&mut rng, $multi, $size, &exp).unwrap();
660714
let private_key = RsaPrivateKey::from_components(

0 commit comments

Comments
 (0)