Skip to content

Commit cd85bc6

Browse files
committed
Fix RSA CRT parameter handling
- Add from_components constructor for RsaPrivateKey - Fix CRT computation by ensuring p > q invariant - Simplify CRT calculation in decrypt and sign methods
1 parent 5f6244f commit cd85bc6

1 file changed

Lines changed: 29 additions & 28 deletions

File tree

hpcrypt-rsa/src/private_key.rs

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,32 @@ impl RsaPrivateKey {
6868
n: BigUint,
6969
e: BigUint,
7070
d: BigUint,
71-
p: BigUint,
72-
q: BigUint,
73-
dp: BigUint,
74-
dq: BigUint,
75-
qinv: BigUint,
71+
mut p: BigUint,
72+
mut q: BigUint,
73+
mut dp: BigUint,
74+
mut dq: BigUint,
75+
mut qinv: BigUint,
7676
) -> Result<Self> {
7777
let public_key = RsaPublicKey::new(n, e)?;
7878

79+
// Ensure p > q (required for CRT correctness)
80+
// If q > p, swap them and recalculate CRT parameters
81+
if q > p {
82+
core::mem::swap(&mut p, &mut q);
83+
core::mem::swap(&mut dp, &mut dq);
84+
85+
// Recalculate qinv = q^-1 mod p (since we swapped p and q)
86+
use crate::primitives::mod_inverse;
87+
use num_traits::One;
88+
89+
qinv = mod_inverse(&q, &p).ok_or(RsaError::KeyGenerationFailed)?;
90+
91+
// Verify the swap is correct
92+
if (&qinv * &q) % &p != BigUint::one() {
93+
return Err(RsaError::KeyGenerationFailed);
94+
}
95+
}
96+
7997
Ok(Self {
8098
public_key,
8199
d,
@@ -231,19 +249,11 @@ impl RsaPrivateKey {
231249
let m2 = c_mod_q.modpow(&self.dq, &self.q);
232250

233251
// h = qinv * (m1 - m2) mod p
234-
// Use modular arithmetic to avoid potential underflow
235252
let h = if m1 >= m2 {
236-
(&self.qinv * (&m1 - &m2)) % &self.p
253+
(&self.qinv * (m1 - &m2)) % &self.p
237254
} else {
238-
// m1 < m2: compute (m1 + p - m2) mod p to avoid underflow
239-
// Since m1 < p and m2 < q, and we ensure p >= q during key generation,
240-
// (m1 + p) will always be >= m2
241-
let sum = &m1 + &self.p;
242-
// Additional safety check to prevent underflow
243-
if sum < m2 {
244-
return Err(RsaError::InvalidCiphertext);
245-
}
246-
(&self.qinv * (sum - &m2)) % &self.p
255+
// Handle m1 < m2: compute h = qinv * (p + m1 - m2) mod p
256+
(&self.qinv * ((&self.p + m1) - &m2)) % &self.p
247257
};
248258

249259
// m = m2 + h * q
@@ -267,20 +277,11 @@ impl RsaPrivateKey {
267277
let m_mod_q = m % &self.q;
268278
let s2 = m_mod_q.modpow(&self.dq, &self.q);
269279

270-
// h = qinv * (s1 - s2) mod p
271-
// Use modular arithmetic to avoid potential underflow
272280
let h = if s1 >= s2 {
273-
(&self.qinv * (&s1 - &s2)) % &self.p
281+
(&self.qinv * (s1 - &s2)) % &self.p
274282
} else {
275-
// s1 < s2: compute (s1 + p - s2) mod p to avoid underflow
276-
// Since s1 < p and s2 < q, and we ensure p >= q during key generation,
277-
// (s1 + p) will always be >= s2
278-
let sum = &s1 + &self.p;
279-
// Additional safety check to prevent underflow
280-
if sum < s2 {
281-
return Err(RsaError::MessageTooLong);
282-
}
283-
(&self.qinv * (sum - &s2)) % &self.p
283+
// Handle s1 < s2: compute h = qinv * (p + s1 - s2) mod p
284+
(&self.qinv * ((&self.p + s1) - &s2)) % &self.p
284285
};
285286

286287
let s = s2 + (h * &self.q);

0 commit comments

Comments
 (0)