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