1use std::sync::{Arc, Mutex};
12
13use super::bigint::{adc, bit_len, from_be_bytes, lt, mac, mod_sub, reduce_be, sbb, to_be_bytes, MontCtx};
14use super::sha2::HashAlg;
15use super::rng;
16use crate::util::ct_eq;
17
18#[derive(Clone)]
19pub struct RsaPublicKey {
20 ctx: MontCtx,
21 e: Vec<u64>,
22 k: usize,
24 mod_bits: usize,
25}
26
27#[derive(Clone)]
28pub struct RsaPrivateKey {
29 pub public: RsaPublicKey,
30 d: Vec<u64>,
31 pub(crate) pkcs1: Option<Vec<u8>>,
33 crt: Option<Crt>,
34 blinding: Arc<Mutex<Option<Blinding>>>,
35}
36
37#[derive(Clone)]
39struct Crt {
40 p: MontCtx,
41 q: MontCtx,
42 dp: Vec<u64>,
43 dq: Vec<u64>,
44 qinv: Vec<u64>,
45}
46
47struct Blinding {
49 vi: Vec<u64>,
50 vf: Vec<u64>,
51}
52
53fn mod_mul(ctx: &MontCtx, a: &[u64], b: &[u64]) -> Vec<u64> {
55 ctx.mul(&ctx.to_mont(a), b)
56}
57
58fn mul_full(a: &[u64], b: &[u64]) -> Vec<u64> {
60 let mut r = vec![0u64; a.len() + b.len()];
61 for (i, &x) in a.iter().enumerate() {
62 let mut carry = 0;
63 for (j, &y) in b.iter().enumerate() {
64 let (lo, hi) = mac(r[i + j], x, y, carry);
65 r[i + j] = lo;
66 carry = hi;
67 }
68 r[i + b.len()] = carry;
69 }
70 r
71}
72
73fn add_assign(r: &mut [u64], b: &[u64]) {
74 let mut carry = 0;
75 for i in 0..r.len() {
76 let (v, c) = adc(r[i], *b.get(i).unwrap_or(&0), carry);
77 r[i] = v;
78 carry = c;
79 }
80}
81
82fn trim_to(mut v: Vec<u64>, n: usize) -> Option<Vec<u64>> {
83 if v[n.min(v.len())..].iter().any(|x| *x != 0) {
84 return None;
85 }
86 v.resize(n, 0);
87 Some(v)
88}
89
90impl std::fmt::Debug for RsaPublicKey {
91 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92 write!(f, "RsaPublicKey({} bits)", self.mod_bits)
93 }
94}
95
96impl std::fmt::Debug for RsaPrivateKey {
97 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98 write!(f, "RsaPrivateKey({} bits)", self.public.mod_bits)
99 }
100}
101
102fn digest_info_prefix(h: HashAlg) -> &'static [u8] {
103 match h {
104 HashAlg::Sha256 => &[
105 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20,
106 ],
107 HashAlg::Sha384 => &[
108 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30,
109 ],
110 HashAlg::Sha512 => &[
111 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40,
112 ],
113 }
114}
115
116fn mgf1(hash: HashAlg, seed: &[u8], len: usize) -> Vec<u8> {
117 let mut out = Vec::with_capacity(len + hash.output_len());
118 let mut counter = 0u32;
119 while out.len() < len {
120 let mut input = seed.to_vec();
121 input.extend_from_slice(&counter.to_be_bytes());
122 out.extend_from_slice(&hash.hash(&input));
123 counter += 1;
124 }
125 out.truncate(len);
126 out
127}
128
129impl RsaPublicKey {
130 pub fn new(n: &[u8], e: &[u8]) -> Option<RsaPublicKey> {
132 let n = {
133 let mut i = 0;
134 while i < n.len() && n[i] == 0 {
135 i += 1;
136 }
137 &n[i..]
138 };
139 if n.len() < 64 || n.len() > 1024 || n[n.len() - 1] & 1 == 0 {
140 return None; }
142 let limbs = n.len().div_ceil(8);
143 let nl = from_be_bytes(n, limbs)?;
144 let el = from_be_bytes(e, limbs)?;
145 if el.iter().all(|x| *x == 0) || !lt(&el, &nl) {
146 return None;
147 }
148 let mod_bits = bit_len(&nl);
149 Some(RsaPublicKey { ctx: MontCtx::new(nl), e: el, k: mod_bits.div_ceil(8), mod_bits })
150 }
151
152 pub fn modulus_bits(&self) -> usize {
153 self.mod_bits
154 }
155
156 pub fn components(&self) -> (Vec<u8>, Vec<u8>) {
158 let n = to_be_bytes(&self.ctx.m, self.k);
159 let mut e = to_be_bytes(&self.e, self.k);
160 while e.len() > 1 && e[0] == 0 {
161 e.remove(0);
162 }
163 (n, e)
164 }
165
166 pub fn size(&self) -> usize {
167 self.k
168 }
169
170 fn encrypt_raw(&self, sig: &[u8]) -> Option<Vec<u8>> {
171 if sig.len() != self.k {
172 return None;
173 }
174 let s = from_be_bytes(sig, self.ctx.n())?;
175 if !lt(&s, &self.ctx.m) {
176 return None;
177 }
178 let m = self.ctx.pow(&s, &self.e, false);
179 Some(to_be_bytes(&m, self.k))
180 }
181
182 pub fn verify_pkcs1(&self, hash: HashAlg, digest: &[u8], sig: &[u8]) -> bool {
184 let em = match self.encrypt_raw(sig) {
185 Some(e) => e,
186 None => return false,
187 };
188 match pkcs1_encode(hash, digest, self.k) {
189 Some(expect) => ct_eq(&em, &expect),
190 None => false,
191 }
192 }
193
194 #[cfg(feature = "sha1")]
197 pub fn verify_pkcs1_sha1(&self, digest: &[u8; 20], sig: &[u8]) -> bool {
198 match (self.encrypt_raw(sig), pkcs1_encode_prefixed(SHA1_DIGEST_INFO, digest, self.k)) {
199 (Some(em), Some(expect)) => ct_eq(&em, &expect),
200 _ => false,
201 }
202 }
203
204 pub fn verify_pss(&self, hash: HashAlg, digest: &[u8], sig: &[u8], salt_len: Option<usize>) -> bool {
207 let em_full = match self.encrypt_raw(sig) {
208 Some(e) => e,
209 None => return false,
210 };
211 let em_bits = self.mod_bits - 1;
212 let em_len = em_bits.div_ceil(8);
213 let em = if em_len < self.k {
214 if em_full[0] != 0 {
215 return false;
216 }
217 &em_full[1..]
218 } else {
219 &em_full[..]
220 };
221 let hlen = hash.output_len();
222 if digest.len() != hlen || em_len < hlen + 2 || em[em_len - 1] != 0xbc {
223 return false;
224 }
225 let masked_db = &em[..em_len - hlen - 1];
226 let h = &em[em_len - hlen - 1..em_len - 1];
227 let top_bits = 8 * em_len - em_bits;
228 let top_mask: u8 = if top_bits == 0 { 0 } else { 0xffu8 << (8 - top_bits) };
229 if masked_db[0] & top_mask != 0 {
230 return false;
231 }
232 let db_mask = mgf1(hash, h, masked_db.len());
233 let mut db: Vec<u8> = masked_db.iter().zip(db_mask.iter()).map(|(a, b)| a ^ b).collect();
234 db[0] &= !top_mask;
235 let pos = match db.iter().position(|b| *b != 0) {
236 Some(p) => p,
237 None => return false,
238 };
239 if db[pos] != 1 {
240 return false;
241 }
242 let salt = &db[pos + 1..];
243 if let Some(sl) = salt_len {
244 if salt.len() != sl {
245 return false;
246 }
247 }
248 let mut mp = vec![0u8; 8];
249 mp.extend_from_slice(digest);
250 mp.extend_from_slice(salt);
251 ct_eq(&hash.hash(&mp), h)
252 }
253}
254
255fn pkcs1_encode(hash: HashAlg, digest: &[u8], k: usize) -> Option<Vec<u8>> {
256 if digest.len() != hash.output_len() {
257 return None;
258 }
259 pkcs1_encode_prefixed(digest_info_prefix(hash), digest, k)
260}
261
262#[cfg(feature = "sha1")]
264const SHA1_DIGEST_INFO: &[u8] = &[0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14];
265
266fn pkcs1_encode_prefixed(prefix: &[u8], digest: &[u8], k: usize) -> Option<Vec<u8>> {
267 let t_len = prefix.len() + digest.len();
268 if k < t_len + 11 {
269 return None;
270 }
271 let mut em = vec![0x00, 0x01];
272 em.resize(k - t_len - 1, 0xff);
273 em.push(0);
274 em.extend_from_slice(prefix);
275 em.extend_from_slice(digest);
276 Some(em)
277}
278
279impl RsaPrivateKey {
280 pub fn new(n: &[u8], e: &[u8], d: &[u8]) -> Option<RsaPrivateKey> {
282 let public = RsaPublicKey::new(n, e)?;
283 let d = from_be_bytes(d, public.ctx.n())?;
284 if !lt(&d, &public.ctx.m) {
285 return None;
286 }
287 Some(RsaPrivateKey { public, d, pkcs1: None, crt: None, blinding: Arc::new(Mutex::new(None)) })
288 }
289
290 pub fn set_crt(&mut self, p: &[u8], q: &[u8], dp: &[u8], dq: &[u8], qinv: &[u8]) -> bool {
293 let strip = |b: &[u8]| -> Vec<u8> { b.iter().copied().skip_while(|x| *x == 0).collect() };
294 let (p, q) = (strip(p), strip(q));
295 if p.is_empty() || q.is_empty() || p.last().unwrap() & 1 == 0 || q.last().unwrap() & 1 == 0 {
296 return false;
297 }
298 let limbs = |b: &[u8]| b.len().div_ceil(8).max(1);
299 let (Some(pl), Some(ql)) = (from_be_bytes(&p, limbs(&p)), from_be_bytes(&q, limbs(&q))) else { return false };
300 match trim_to(mul_full(&pl, &ql), self.public.ctx.n()) {
302 Some(n) if n == self.public.ctx.m => {}
303 _ => return false,
304 }
305 let (Some(dp), Some(dq), Some(qinv)) = (from_be_bytes(&strip(dp), pl.len()), from_be_bytes(&strip(dq), ql.len()), from_be_bytes(&strip(qinv), pl.len())) else { return false };
306 self.crt = Some(Crt { p: MontCtx::new(pl), q: MontCtx::new(ql), dp, dq, qinv });
307 true
308 }
309
310 pub fn has_crt(&self) -> bool {
312 self.crt.is_some()
313 }
314
315 fn crt_pow(&self, crt: &Crt, c: &[u64]) -> Option<Vec<u64>> {
317 let m1 = crt.p.pow(&crt.p.reduce(c), &crt.dp, true);
318 let m2 = crt.q.pow(&crt.q.reduce(c), &crt.dq, true);
319 let m2p = crt.p.reduce(&m2);
320 let mut diff = vec![0u64; crt.p.n()];
321 mod_sub(&mut diff, &m1, &m2p, &crt.p.m);
322 let h = mod_mul(&crt.p, &crt.qinv, &diff);
323 let mut s = mul_full(&h, &crt.q.m);
324 add_assign(&mut s, &m2);
325 trim_to(s, self.public.ctx.n())
326 }
327
328 fn next_blinding(&self) -> Option<(Vec<u64>, Vec<u64>)> {
330 let ctx = &self.public.ctx;
331 let mut g = self.blinding.lock().unwrap();
332 if g.is_none() {
333 if self.public.e.iter().skip(1).any(|x| *x != 0) {
335 return None;
336 }
337 let e = self.public.e[0];
338 let mut ed = vec![0u64; self.d.len() + 1];
339 let mut carry = 0;
340 for (i, &x) in self.d.iter().enumerate() {
341 let (lo, hi) = mac(0, x, e, carry);
342 ed[i] = lo;
343 carry = hi;
344 }
345 ed[self.d.len()] = carry;
346 let mut borrow = 0;
347 for (i, limb) in ed.iter_mut().enumerate() {
348 let (v, b) = sbb(*limb, if i == 0 { 2 } else { 0 }, borrow);
349 *limb = v;
350 borrow = b;
351 }
352 let r = loop {
353 let r = reduce_be(&rng::bytes(self.public.k + 8), &ctx.m);
354 if bit_len(&r) > 64 {
355 break r;
356 }
357 };
358 let vi = ctx.pow(&r, &self.public.e, false);
359 let vf = ctx.pow(&r, &ed, true);
360 if mod_mul(ctx, &vi, &ctx.pow(&vf, &self.public.e, false)).iter().enumerate().any(|(i, x)| *x != (i == 0) as u64) {
361 return None; }
363 *g = Some(Blinding { vi, vf });
364 }
365 let b = g.as_mut().unwrap();
366 let out = (b.vi.clone(), b.vf.clone());
367 b.vi = mod_mul(ctx, &b.vi, &b.vi);
368 b.vf = mod_mul(ctx, &b.vf, &b.vf);
369 Some(out)
370 }
371
372 pub fn pkcs1_der(&self) -> Option<&[u8]> {
375 self.pkcs1.as_deref()
376 }
377
378 fn decrypt_raw(&self, em: &[u8]) -> Option<Vec<u8>> {
379 let m = from_be_bytes(em, self.public.ctx.n())?;
380 if !lt(&m, &self.public.ctx.m) {
381 return None;
382 }
383 let ctx = &self.public.ctx;
384 let blinding = self.next_blinding();
385 let mb = match &blinding {
386 Some((vi, _)) => mod_mul(ctx, &m, vi),
387 None => m.clone(),
388 };
389 let sb = match &self.crt {
390 Some(crt) => self.crt_pow(crt, &mb)?,
391 None => ctx.pow(&mb, &self.d, true),
392 };
393 let s = match &blinding {
394 Some((_, vf)) => mod_mul(ctx, &sb, vf),
395 None => sb,
396 };
397 let sig = to_be_bytes(&s, self.public.k);
398 if self.public.encrypt_raw(&sig)? != to_be_bytes(&m, self.public.k) {
400 return None;
401 }
402 Some(sig)
403 }
404
405 pub fn sign_pkcs1(&self, hash: HashAlg, digest: &[u8]) -> Option<Vec<u8>> {
406 let em = pkcs1_encode(hash, digest, self.public.k)?;
407 self.decrypt_raw(&em)
408 }
409
410 #[cfg(feature = "sha1")]
413 pub fn sign_pkcs1_sha1(&self, digest: &[u8; 20]) -> Option<Vec<u8>> {
414 let em = pkcs1_encode_prefixed(SHA1_DIGEST_INFO, digest, self.public.k)?;
415 self.decrypt_raw(&em)
416 }
417
418 pub fn sign_pss(&self, hash: HashAlg, digest: &[u8]) -> Option<Vec<u8>> {
420 let salt = rng::bytes(hash.output_len());
421 self.sign_pss_with_salt(hash, digest, &salt)
422 }
423
424 pub fn sign_pss_with_salt(&self, hash: HashAlg, digest: &[u8], salt: &[u8]) -> Option<Vec<u8>> {
425 let hlen = hash.output_len();
426 let em_bits = self.public.mod_bits - 1;
427 let em_len = em_bits.div_ceil(8);
428 if digest.len() != hlen || em_len < hlen + salt.len() + 2 {
429 return None;
430 }
431 let mut mp = vec![0u8; 8];
432 mp.extend_from_slice(digest);
433 mp.extend_from_slice(salt);
434 let h = hash.hash(&mp).to_vec();
435 let db_len = em_len - hlen - 1;
436 let mut db = vec![0u8; db_len - salt.len() - 1];
437 db.push(1);
438 db.extend_from_slice(salt);
439 let mask = mgf1(hash, &h, db_len);
440 let mut em: Vec<u8> = db.iter().zip(mask.iter()).map(|(a, b)| a ^ b).collect();
441 let top_bits = 8 * em_len - em_bits;
442 if top_bits > 0 {
443 em[0] &= 0xff >> top_bits;
444 }
445 em.extend_from_slice(&h);
446 em.push(0xbc);
447 let mut full = vec![0u8; self.public.k - em_len];
448 full.extend(em);
449 self.decrypt_raw(&full)
450 }
451}
452
453#[cfg(test)]
454mod tests {
455 use super::*;
456 use crate::util::unhex;
457
458 const N: &str = "c7f6a2d7ec1d1a1ac3cd29b2a6a04e5e3e4b2aca69f2c3c4e94f3dbfc40b2c7c\
4612b0b0f13c69c43c4a18c0bfa6e7bc5ff10a36eb4b55cb43e3098ce3a85c3e1d1\
4626f4f80bd2a9c1d13ba88da2bc4bf1ad3b6d15d5d71d6f9c6c55c0a1f33f01a1e\
463ab38f19c0e7c70e9c6c2fb7e43cd7d5e2c91b88dbdc7aa2a4b9cb7df5dc33d81";
464
465 #[test]
466 fn rejects_bad_keys() {
467 assert!(RsaPublicKey::new(&unhex("0f"), &[3]).is_none());
468 let mut even = unhex(N);
469 let last = even.len() - 1;
470 even[last] &= 0xfe;
471 assert!(RsaPublicKey::new(&even, &[1, 0, 1]).is_none());
472 }
473}
474
475#[cfg(test)]
476mod micro {
477 use super::super::bigint::{mont_mul, MontCtx};
478 #[test]
479 #[ignore]
480 fn rsa_breakdown() {
481 let key = match crate::keys::PrivateKey::from_pem(include_bytes!("../../testdata/rsa2048.pkcs1.pem")).unwrap() {
482 crate::keys::PrivateKey::Rsa(k) => k,
483 _ => unreachable!(),
484 };
485 let crt = key.crt.as_ref().unwrap();
486 let ctx: &MontCtx = &crt.p;
487 let a = ctx.to_mont(&vec![3u64; 16]);
488 let mut r = a.clone();
489 let mut t = vec![0u64; 18];
490 let n = 200_000;
491 let s = std::time::Instant::now();
492 for _ in 0..n {
493 let x = r.clone();
494 mont_mul(&mut r, &x, &a, &ctx.m, ctx.m0inv, &mut t);
495 }
496 println!("mont_mul 16 limbs: {:.0} ns", s.elapsed().as_nanos() as f64 / n as f64);
497 let s = std::time::Instant::now();
498 for _ in 0..200 {
499 std::hint::black_box(ctx.pow(&a, &crt.dp, true));
500 }
501 println!("pow 1024: {:.1} us", s.elapsed().as_nanos() as f64 / 200.0 / 1e3);
502 let dg = [1u8; 32];
503 let s = std::time::Instant::now();
504 for _ in 0..200 {
505 std::hint::black_box(key.sign_pss(crate::crypto::sha2::HashAlg::Sha256, &dg));
506 }
507 println!("sign: {:.1} us", s.elapsed().as_nanos() as f64 / 200.0 / 1e3);
508 }
509}