1use std::fmt;
14use std::time::{SystemTime, UNIX_EPOCH};
15
16use ferogram_crypto::{AuthKey, aes, check_p_and_g, factorize, generate_key_data_from_nonce, rsa};
17use ferogram_tl_types::{Cursor, Deserializable, Serializable};
18use num_bigint::BigUint;
19use sha1::{Digest, Sha1};
20
21fn tl_serialize_bytes(v: &[u8]) -> Vec<u8> {
27 let len = v.len();
28 let mut out = Vec::new();
29 if len < 254 {
30 out.push(len as u8);
31 out.extend_from_slice(v);
32 let total = 1 + len;
33 let pad = (4 - total % 4) % 4;
34 out.extend(std::iter::repeat_n(0u8, pad));
35 } else {
36 out.push(0xfe);
37 out.push((len & 0xff) as u8);
38 out.push(((len >> 8) & 0xff) as u8);
39 out.push(((len >> 16) & 0xff) as u8);
40 out.extend_from_slice(v);
41 let total = 4 + len;
42 let pad = (4 - total % 4) % 4;
43 out.extend(std::iter::repeat_n(0u8, pad));
44 }
45 out
46}
47
48fn serialize_pq_inner_data_dc(
52 pq: &[u8],
53 p: &[u8],
54 q: &[u8],
55 nonce: &[u8; 16],
56 server_nonce: &[u8; 16],
57 new_nonce: &[u8; 32],
58 dc_id: i32,
59) -> Vec<u8> {
60 let mut out = Vec::new();
61 out.extend_from_slice(&0xa9f55f95_u32.to_le_bytes());
63 out.extend(tl_serialize_bytes(pq));
64 out.extend(tl_serialize_bytes(p));
65 out.extend(tl_serialize_bytes(q));
66 out.extend_from_slice(nonce);
67 out.extend_from_slice(server_nonce);
68 out.extend_from_slice(new_nonce);
69 out.extend_from_slice(&dc_id.to_le_bytes());
70 out
71}
72
73#[allow(clippy::too_many_arguments)]
75fn serialize_pq_inner_data_temp_dc(
76 pq: &[u8],
77 p: &[u8],
78 q: &[u8],
79 nonce: &[u8; 16],
80 server_nonce: &[u8; 16],
81 new_nonce: &[u8; 32],
82 dc_id: i32,
83 expires_in: i32,
84) -> Vec<u8> {
85 let mut out = Vec::new();
86 out.extend_from_slice(&0x56fddf88_u32.to_le_bytes()); out.extend(tl_serialize_bytes(pq));
88 out.extend(tl_serialize_bytes(p));
89 out.extend(tl_serialize_bytes(q));
90 out.extend_from_slice(nonce);
91 out.extend_from_slice(server_nonce);
92 out.extend_from_slice(new_nonce);
93 out.extend_from_slice(&dc_id.to_le_bytes());
94 out.extend_from_slice(&expires_in.to_le_bytes()); out
96}
97
98#[allow(missing_docs)]
100#[derive(Clone, Debug, PartialEq)]
101pub enum Error {
102 InvalidNonce {
103 got: [u8; 16],
104 expected: [u8; 16],
105 },
106 InvalidPqSize {
107 size: usize,
108 },
109 UnknownFingerprints {
110 fingerprints: Vec<i64>,
111 },
112 DhParamsFail,
113 InvalidServerNonce {
114 got: [u8; 16],
115 expected: [u8; 16],
116 },
117 EncryptedResponseNotPadded {
118 len: usize,
119 },
120 InvalidDhInnerData {
121 error: ferogram_tl_types::deserialize::Error,
122 },
123 InvalidDhPrime {
124 source: ferogram_crypto::DhError,
125 },
126 GParameterOutOfRange {
127 value: BigUint,
128 low: BigUint,
129 high: BigUint,
130 },
131 DhGenRetry,
132 DhGenFail,
133 InvalidAnswerHash {
134 got: [u8; 20],
135 expected: [u8; 20],
136 },
137 InvalidNewNonceHash {
138 got: [u8; 16],
139 expected: [u8; 16],
140 },
141}
142
143impl std::error::Error for Error {}
144
145impl fmt::Display for Error {
146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147 match self {
148 Self::InvalidNonce { got, expected } => {
149 write!(f, "nonce mismatch: got {got:?}, expected {expected:?}")
150 }
151 Self::InvalidPqSize { size } => write!(f, "pq size {size} invalid (expected 8)"),
152 Self::UnknownFingerprints { fingerprints } => {
153 write!(f, "no known fingerprint in {fingerprints:?}")
154 }
155 Self::DhParamsFail => write!(f, "server returned DH params failure"),
156 Self::InvalidServerNonce { got, expected } => write!(
157 f,
158 "server_nonce mismatch: got {got:?}, expected {expected:?}"
159 ),
160 Self::EncryptedResponseNotPadded { len } => {
161 write!(f, "encrypted answer len {len} is not 16-byte aligned")
162 }
163 Self::InvalidDhInnerData { error } => {
164 write!(f, "DH inner data deserialization error: {error}")
165 }
166 Self::InvalidDhPrime { source } => {
167 write!(f, "DH prime/generator validation failed: {source}")
168 }
169 Self::GParameterOutOfRange { value, low, high } => {
170 write!(f, "g={value} not in range ({low}, {high})")
171 }
172 Self::DhGenRetry => write!(f, "DH gen retry requested"),
173 Self::DhGenFail => write!(f, "DH gen failed"),
174 Self::InvalidAnswerHash { got, expected } => write!(
175 f,
176 "answer hash mismatch: got {got:?}, expected {expected:?}"
177 ),
178 Self::InvalidNewNonceHash { got, expected } => write!(
179 f,
180 "new nonce hash mismatch: got {got:?}, expected {expected:?}"
181 ),
182 }
183 }
184}
185
186pub struct Step1 {
188 nonce: [u8; 16],
189}
190
191#[derive(Clone)]
193pub struct Step2 {
194 nonce: [u8; 16],
195 server_nonce: [u8; 16],
196 new_nonce: [u8; 32],
197}
198
199#[derive(Clone)]
202pub struct DhParamsForRetry {
203 pub dh_prime: Vec<u8>,
205 pub g: u32,
207 pub g_a: Vec<u8>,
209 pub server_time: i32,
211 pub aes_key: [u8; 32],
213 pub aes_iv: [u8; 32],
215}
216
217pub struct Step3 {
219 nonce: [u8; 16],
220 server_nonce: [u8; 16],
221 new_nonce: [u8; 32],
222 time_offset: i32,
223 auth_key: [u8; 256],
225 pub dh_params: DhParamsForRetry,
228}
229
230pub enum FinishResult {
233 Done(Finished),
235 Retry {
238 retry_id: i64,
240 dh_params: DhParamsForRetry,
242 nonce: [u8; 16],
244 server_nonce: [u8; 16],
246 new_nonce: [u8; 32],
248 },
249}
250
251#[derive(Clone, Debug, PartialEq)]
253pub struct Finished {
254 pub auth_key: [u8; 256],
256 pub time_offset: i32,
258 pub first_salt: i64,
260}
261
262pub fn step1() -> Result<(ferogram_tl_types::functions::ReqPqMulti, Step1), Error> {
264 let mut buf = [0u8; 16];
265 getrandom::getrandom(&mut buf).expect("getrandom");
266 do_step1(&buf)
267}
268
269fn do_step1(random: &[u8; 16]) -> Result<(ferogram_tl_types::functions::ReqPqMulti, Step1), Error> {
270 let nonce = *random;
271 Ok((
272 ferogram_tl_types::functions::ReqPqMulti { nonce },
273 Step1 { nonce },
274 ))
275}
276
277pub fn step2(
283 data: Step1,
284 response: ferogram_tl_types::enums::ResPq,
285 dc_id: i32,
286) -> Result<(ferogram_tl_types::functions::ReqDhParams, Step2), Error> {
287 let mut rnd = [0u8; 256];
288 getrandom::getrandom(&mut rnd).expect("getrandom");
289 do_step2(data, response, &rnd, dc_id)
290}
291
292pub fn step2_temp(
296 data: Step1,
297 response: ferogram_tl_types::enums::ResPq,
298 dc_id: i32,
299 expires_in: i32,
300) -> Result<(ferogram_tl_types::functions::ReqDhParams, Step2), Error> {
301 let mut rnd = [0u8; 256];
302 getrandom::getrandom(&mut rnd).expect("getrandom");
303 do_step2_temp(data, response, &rnd, dc_id, expires_in)
304}
305
306fn do_step2_temp(
307 data: Step1,
308 response: ferogram_tl_types::enums::ResPq,
309 random: &[u8; 256],
310 dc_id: i32,
311 expires_in: i32,
312) -> Result<(ferogram_tl_types::functions::ReqDhParams, Step2), Error> {
313 let Step1 { nonce } = data;
314 let ferogram_tl_types::enums::ResPq::ResPq(res_pq) = response;
315 check_nonce(&res_pq.nonce, &nonce)?;
316 if res_pq.pq.len() != 8 {
317 return Err(Error::InvalidPqSize {
318 size: res_pq.pq.len(),
319 });
320 }
321 let pq = u64::from_be_bytes(res_pq.pq.as_slice().try_into().unwrap());
322 let (p, q) = factorize(pq);
323 let mut new_nonce = [0u8; 32];
324 new_nonce.copy_from_slice(&random[..32]);
325 let rnd224: &[u8; 224] = random[32..].try_into().unwrap();
326 fn trim_be(v: u64) -> Vec<u8> {
327 let b = v.to_be_bytes();
328 let skip = b.iter().position(|&x| x != 0).unwrap_or(7);
329 b[skip..].to_vec()
330 }
331 let p_bytes = trim_be(p);
332 let q_bytes = trim_be(q);
333 let pq_inner = serialize_pq_inner_data_temp_dc(
334 &pq.to_be_bytes(),
335 &p_bytes,
336 &q_bytes,
337 &nonce,
338 &res_pq.server_nonce,
339 &new_nonce,
340 dc_id,
341 expires_in,
342 );
343 let fingerprint = res_pq
344 .server_public_key_fingerprints
345 .iter()
346 .copied()
347 .find(|&fp| key_for_fingerprint(fp).is_some())
348 .ok_or_else(|| Error::UnknownFingerprints {
349 fingerprints: res_pq.server_public_key_fingerprints.clone(),
350 })?;
351 let key = key_for_fingerprint(fingerprint).unwrap();
352 let ciphertext = rsa::encrypt_hashed(&pq_inner, &key, rnd224);
353 Ok((
354 ferogram_tl_types::functions::ReqDhParams {
355 nonce,
356 server_nonce: res_pq.server_nonce,
357 p: p_bytes,
358 q: q_bytes,
359 public_key_fingerprint: fingerprint,
360 encrypted_data: ciphertext,
361 },
362 Step2 {
363 nonce,
364 server_nonce: res_pq.server_nonce,
365 new_nonce,
366 },
367 ))
368}
369
370fn do_step2(
371 data: Step1,
372 response: ferogram_tl_types::enums::ResPq,
373 random: &[u8; 256],
374 dc_id: i32,
375) -> Result<(ferogram_tl_types::functions::ReqDhParams, Step2), Error> {
376 let Step1 { nonce } = data;
377
378 let ferogram_tl_types::enums::ResPq::ResPq(res_pq) = response;
380
381 check_nonce(&res_pq.nonce, &nonce)?;
382
383 if res_pq.pq.len() != 8 {
384 return Err(Error::InvalidPqSize {
385 size: res_pq.pq.len(),
386 });
387 }
388
389 let pq = u64::from_be_bytes(res_pq.pq.as_slice().try_into().unwrap());
390 let (p, q) = factorize(pq);
391
392 let mut new_nonce = [0u8; 32];
393 new_nonce.copy_from_slice(&random[..32]);
394
395 let rnd224: &[u8; 224] = random[32..].try_into().unwrap();
397
398 fn trim_be(v: u64) -> Vec<u8> {
399 let b = v.to_be_bytes();
400 let skip = b.iter().position(|&x| x != 0).unwrap_or(7);
401 b[skip..].to_vec()
402 }
403
404 let p_bytes = trim_be(p);
405 let q_bytes = trim_be(q);
406
407 let pq_inner = serialize_pq_inner_data_dc(
411 &pq.to_be_bytes(),
412 &p_bytes,
413 &q_bytes,
414 &nonce,
415 &res_pq.server_nonce,
416 &new_nonce,
417 dc_id,
418 );
419
420 let fingerprint = res_pq
421 .server_public_key_fingerprints
422 .iter()
423 .copied()
424 .find(|&fp| key_for_fingerprint(fp).is_some())
425 .ok_or_else(|| Error::UnknownFingerprints {
426 fingerprints: res_pq.server_public_key_fingerprints.clone(),
427 })?;
428
429 let key = key_for_fingerprint(fingerprint).unwrap();
430 let ciphertext = rsa::encrypt_hashed(&pq_inner, &key, rnd224);
431
432 Ok((
433 ferogram_tl_types::functions::ReqDhParams {
434 nonce,
435 server_nonce: res_pq.server_nonce,
436 p: p_bytes,
437 q: q_bytes,
438 public_key_fingerprint: fingerprint,
439 encrypted_data: ciphertext,
440 },
441 Step2 {
442 nonce,
443 server_nonce: res_pq.server_nonce,
444 new_nonce,
445 },
446 ))
447}
448
449pub fn step3(
455 data: Step2,
456 response: ferogram_tl_types::enums::ServerDhParams,
457) -> Result<(ferogram_tl_types::functions::SetClientDhParams, Step3), Error> {
458 let mut rnd = [0u8; 272];
459 getrandom::getrandom(&mut rnd).expect("getrandom");
460 let now = SystemTime::now()
461 .duration_since(UNIX_EPOCH)
462 .unwrap()
463 .as_secs() as i32;
464 do_step3(data, response, &rnd, now, 0)
465}
466
467pub fn retry_step3(
471 dh_params: &DhParamsForRetry,
472 nonce: [u8; 16],
473 server_nonce: [u8; 16],
474 new_nonce: [u8; 32],
475 retry_id: i64,
476) -> Result<(ferogram_tl_types::functions::SetClientDhParams, Step3), Error> {
477 let mut rnd = [0u8; 272];
478 getrandom::getrandom(&mut rnd).expect("getrandom");
479 let now = SystemTime::now()
480 .duration_since(UNIX_EPOCH)
481 .unwrap()
482 .as_secs() as i32;
483 generate_client_dh_params(
484 dh_params,
485 nonce,
486 server_nonce,
487 new_nonce,
488 retry_id,
489 &rnd,
490 now,
491 )
492}
493
494fn generate_client_dh_params(
495 dh: &DhParamsForRetry,
496 nonce: [u8; 16],
497 server_nonce: [u8; 16],
498 new_nonce: [u8; 32],
499 retry_id: i64,
500 random: &[u8; 272],
501 now: i32,
502) -> Result<(ferogram_tl_types::functions::SetClientDhParams, Step3), Error> {
503 let dh_prime = BigUint::from_bytes_be(&dh.dh_prime);
504 let g = BigUint::from(dh.g);
505 let g_a = BigUint::from_bytes_be(&dh.g_a);
506 let time_offset = dh.server_time - now;
507
508 let b = BigUint::from_bytes_be(&random[..256]);
509 let g_b = g.modpow(&b, &dh_prime);
510
511 let one = BigUint::from(1u32);
512 let safety = one.clone() << (2048 - 64);
513 check_g_in_range(&g_b, &one, &(&dh_prime - &one))?;
514 check_g_in_range(&g_b, &safety, &(&dh_prime - &safety))?;
515
516 let client_dh_inner = ferogram_tl_types::enums::ClientDhInnerData::ClientDhInnerData(
517 ferogram_tl_types::types::ClientDhInnerData {
518 nonce,
519 server_nonce,
520 retry_id,
521 g_b: g_b.to_bytes_be(),
522 },
523 )
524 .to_bytes();
525
526 let digest: [u8; 20] = {
527 let mut sha = Sha1::new();
528 sha.update(&client_dh_inner);
529 sha.finalize().into()
530 };
531
532 let pad_len = (16 - ((20 + client_dh_inner.len()) % 16)) % 16;
533 let rnd16 = &random[256..256 + pad_len.min(16)];
534
535 let mut hashed = Vec::with_capacity(20 + client_dh_inner.len() + pad_len);
536 hashed.extend_from_slice(&digest);
537 hashed.extend_from_slice(&client_dh_inner);
538 hashed.extend_from_slice(&rnd16[..pad_len]);
539
540 let key: [u8; 32] = dh.aes_key;
541 let iv: [u8; 32] = dh.aes_iv;
542 aes::ige_encrypt(&mut hashed, &key, &iv);
543
544 let mut auth_key_bytes = [0u8; 256];
546 let gab_bytes = g_a.modpow(&b, &dh_prime).to_bytes_be();
547 let skip = 256 - gab_bytes.len();
548 auth_key_bytes[skip..].copy_from_slice(&gab_bytes);
549
550 Ok((
551 ferogram_tl_types::functions::SetClientDhParams {
552 nonce,
553 server_nonce,
554 encrypted_data: hashed,
555 },
556 Step3 {
557 nonce,
558 server_nonce,
559 new_nonce,
560 time_offset,
561 auth_key: auth_key_bytes,
562 dh_params: dh.clone(),
563 },
564 ))
565}
566
567fn do_step3(
568 data: Step2,
569 response: ferogram_tl_types::enums::ServerDhParams,
570 random: &[u8; 272],
571 now: i32,
572 retry_id: i64,
573) -> Result<(ferogram_tl_types::functions::SetClientDhParams, Step3), Error> {
574 let Step2 {
575 nonce,
576 server_nonce,
577 new_nonce,
578 } = data;
579
580 let mut server_dh_ok = match response {
581 ferogram_tl_types::enums::ServerDhParams::Fail(f) => {
582 check_nonce(&f.nonce, &nonce)?;
583 check_server_nonce(&f.server_nonce, &server_nonce)?;
584 return Err(Error::DhParamsFail);
585 }
586 ferogram_tl_types::enums::ServerDhParams::Ok(x) => x,
587 };
588
589 check_nonce(&server_dh_ok.nonce, &nonce)?;
590 check_server_nonce(&server_dh_ok.server_nonce, &server_nonce)?;
591
592 if server_dh_ok.encrypted_answer.len() % 16 != 0 {
593 return Err(Error::EncryptedResponseNotPadded {
594 len: server_dh_ok.encrypted_answer.len(),
595 });
596 }
597
598 let (key_arr, iv_arr) = generate_key_data_from_nonce(&server_nonce, &new_nonce);
599 aes::ige_decrypt(&mut server_dh_ok.encrypted_answer, &key_arr, &iv_arr);
600 let plain = server_dh_ok.encrypted_answer;
601
602 let got_hash: [u8; 20] = plain[..20].try_into().unwrap();
603 let mut cursor = Cursor::from_slice(&plain[20..]);
604
605 let inner = match ferogram_tl_types::enums::ServerDhInnerData::deserialize(&mut cursor) {
606 Ok(ferogram_tl_types::enums::ServerDhInnerData::ServerDhInnerData(x)) => x,
607 Err(e) => return Err(Error::InvalidDhInnerData { error: e }),
608 };
609
610 let expected_hash: [u8; 20] = {
611 let mut sha = Sha1::new();
612 sha.update(&plain[20..20 + cursor.pos()]);
613 sha.finalize().into()
614 };
615 if got_hash != expected_hash {
616 return Err(Error::InvalidAnswerHash {
617 got: got_hash,
618 expected: expected_hash,
619 });
620 }
621
622 check_nonce(&inner.nonce, &nonce)?;
623 check_server_nonce(&inner.server_nonce, &server_nonce)?;
624
625 check_p_and_g(&inner.dh_prime, inner.g as u32)
626 .map_err(|source| Error::InvalidDhPrime { source })?;
627
628 let dh_prime_bn = BigUint::from_bytes_be(&inner.dh_prime);
630 let one = BigUint::from(1u32);
631 let g_a_bn = BigUint::from_bytes_be(&inner.g_a);
632 let safety = one.clone() << (2048 - 64);
633 check_g_in_range(&g_a_bn, &safety, &(&dh_prime_bn - &safety))?;
634
635 let dh = DhParamsForRetry {
636 dh_prime: inner.dh_prime,
637 g: inner.g as u32,
638 g_a: inner.g_a,
639 server_time: inner.server_time,
640 aes_key: key_arr,
641 aes_iv: iv_arr,
642 };
643
644 generate_client_dh_params(&dh, nonce, server_nonce, new_nonce, retry_id, random, now)
645}
646
647pub fn finish(
654 data: Step3,
655 response: ferogram_tl_types::enums::SetClientDhParamsAnswer,
656) -> Result<FinishResult, Error> {
657 let Step3 {
658 nonce,
659 server_nonce,
660 new_nonce,
661 time_offset,
662 auth_key: auth_key_bytes,
663 dh_params,
664 } = data;
665
666 struct DhData {
667 nonce: [u8; 16],
668 server_nonce: [u8; 16],
669 hash: [u8; 16],
670 num: u8,
671 }
672
673 let dh = match response {
674 ferogram_tl_types::enums::SetClientDhParamsAnswer::DhGenOk(x) => DhData {
676 nonce: x.nonce,
677 server_nonce: x.server_nonce,
678 hash: x.new_nonce_hash1,
679 num: 1,
680 },
681 ferogram_tl_types::enums::SetClientDhParamsAnswer::DhGenRetry(x) => DhData {
682 nonce: x.nonce,
683 server_nonce: x.server_nonce,
684 hash: x.new_nonce_hash2,
685 num: 2,
686 },
687 ferogram_tl_types::enums::SetClientDhParamsAnswer::DhGenFail(x) => DhData {
688 nonce: x.nonce,
689 server_nonce: x.server_nonce,
690 hash: x.new_nonce_hash3,
691 num: 3,
692 },
693 };
694
695 check_nonce(&dh.nonce, &nonce)?;
696 check_server_nonce(&dh.server_nonce, &server_nonce)?;
697
698 let auth_key = AuthKey::from_bytes(auth_key_bytes);
699 let expected_hash = auth_key.calc_new_nonce_hash(&new_nonce, dh.num);
700 check_new_nonce_hash(&dh.hash, &expected_hash)?;
701
702 let first_salt = {
703 let mut buf = [0u8; 8];
704 for ((dst, a), b) in buf.iter_mut().zip(&new_nonce[..8]).zip(&server_nonce[..8]) {
705 *dst = a ^ b;
706 }
707 i64::from_le_bytes(buf)
708 };
709
710 match dh.num {
711 1 => Ok(FinishResult::Done(Finished {
712 auth_key: auth_key.to_bytes(),
713 time_offset,
714 first_salt,
715 })),
716 2 => {
717 let aux_hash: [u8; 20] = {
719 let mut sha = Sha1::new();
720 sha.update(auth_key.to_bytes());
721 sha.finalize().into()
722 };
723 let retry_id = i64::from_le_bytes(aux_hash[..8].try_into().unwrap());
724 Ok(FinishResult::Retry {
725 retry_id,
726 dh_params,
727 nonce,
728 server_nonce,
729 new_nonce,
730 })
731 }
732 _ => Err(Error::DhGenFail),
733 }
734}
735
736fn check_nonce(got: &[u8; 16], expected: &[u8; 16]) -> Result<(), Error> {
737 if got == expected {
738 Ok(())
739 } else {
740 Err(Error::InvalidNonce {
741 got: *got,
742 expected: *expected,
743 })
744 }
745}
746fn check_server_nonce(got: &[u8; 16], expected: &[u8; 16]) -> Result<(), Error> {
747 if got == expected {
748 Ok(())
749 } else {
750 Err(Error::InvalidServerNonce {
751 got: *got,
752 expected: *expected,
753 })
754 }
755}
756fn check_new_nonce_hash(got: &[u8; 16], expected: &[u8; 16]) -> Result<(), Error> {
757 if got == expected {
758 Ok(())
759 } else {
760 Err(Error::InvalidNewNonceHash {
761 got: *got,
762 expected: *expected,
763 })
764 }
765}
766fn check_g_in_range(val: &BigUint, lo: &BigUint, hi: &BigUint) -> Result<(), Error> {
767 if lo < val && val < hi {
768 Ok(())
769 } else {
770 Err(Error::GParameterOutOfRange {
771 value: val.clone(),
772 low: lo.clone(),
773 high: hi.clone(),
774 })
775 }
776}
777
778#[allow(clippy::unreadable_literal)]
780pub fn key_for_fingerprint(fp: i64) -> Option<rsa::Key> {
781 Some(match fp {
782 -3414540481677951611 => rsa::Key::new(
784 "29379598170669337022986177149456128565388431120058863768162556424047512191330847455146576344487764408661701890505066208632169112269581063774293102577308490531282748465986139880977280302242772832972539403531316010870401287642763009136156734339538042419388722777357134487746169093539093850251243897188928735903389451772730245253062963384108812842079887538976360465290946139638691491496062099570836476454855996319192747663615955633778034897140982517446405334423701359108810182097749467210509584293428076654573384828809574217079944388301239431309115013843331317877374435868468779972014486325557807783825502498215169806323",
785 "65537",
786 )?,
787 -5595554452916591101 => rsa::Key::new(
789 "25342889448840415564971689590713473206898847759084779052582026594546022463853940585885215951168491965708222649399180603818074200620463776135424884632162512403163793083921641631564740959529419359595852941166848940585952337613333022396096584117954892216031229237302943701877588456738335398602461675225081791820393153757504952636234951323237820036543581047826906120927972487366805292115792231423684261262330394324750785450942589751755390156647751460719351439969059949569615302809050721500330239005077889855323917509948255722081644689442127297605422579707142646660768825302832201908302295573257427896031830742328565032949",
790 "65537",
791 )?,
792 _ => return None,
793 })
794}