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