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