1use std::fmt;
17use std::time::{SystemTime, UNIX_EPOCH};
18
19use layer_crypto::{AuthKey, aes, check_p_and_g, factorize, generate_key_data_from_nonce, rsa};
20use layer_tl_types::{Cursor, Deserializable, Serializable};
21use num_bigint::{BigUint, ToBigUint};
22use sha1::{Digest, Sha1};
23
24#[allow(missing_docs)]
28#[derive(Clone, Debug, PartialEq)]
29pub enum Error {
30 InvalidNonce { got: [u8; 16], expected: [u8; 16] },
31 InvalidPqSize { size: usize },
32 UnknownFingerprints { fingerprints: Vec<i64> },
33 DhParamsFail,
34 InvalidServerNonce { got: [u8; 16], expected: [u8; 16] },
35 EncryptedResponseNotPadded { len: usize },
36 InvalidDhInnerData { error: layer_tl_types::deserialize::Error },
37 InvalidDhPrime { source: layer_crypto::DhError },
38 GParameterOutOfRange { value: BigUint, low: BigUint, high: BigUint },
39 DhGenRetry,
40 DhGenFail,
41 InvalidAnswerHash { got: [u8; 20], expected: [u8; 20] },
42 InvalidNewNonceHash { got: [u8; 16], expected: [u8; 16] },
43}
44
45impl std::error::Error for Error {}
46
47impl fmt::Display for Error {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 match self {
50 Self::InvalidNonce { got, expected }
51 => write!(f, "nonce mismatch: got {got:?}, expected {expected:?}"),
52 Self::InvalidPqSize { size }
53 => write!(f, "pq size {size} invalid (expected 8)"),
54 Self::UnknownFingerprints { fingerprints }
55 => write!(f, "no known fingerprint in {fingerprints:?}"),
56 Self::DhParamsFail
57 => write!(f, "server returned DH params failure"),
58 Self::InvalidServerNonce { got, expected }
59 => write!(f, "server_nonce mismatch: got {got:?}, expected {expected:?}"),
60 Self::EncryptedResponseNotPadded { len }
61 => write!(f, "encrypted answer len {len} is not 16-byte aligned"),
62 Self::InvalidDhInnerData { error }
63 => write!(f, "DH inner data deserialization error: {error}"),
64 Self::InvalidDhPrime { source }
65 => write!(f, "DH prime/generator validation failed: {source}"),
66 Self::GParameterOutOfRange { value, low, high }
67 => write!(f, "g={value} not in range ({low}, {high})"),
68 Self::DhGenRetry => write!(f, "DH gen retry requested"),
69 Self::DhGenFail => write!(f, "DH gen failed"),
70 Self::InvalidAnswerHash { got, expected }
71 => write!(f, "answer hash mismatch: got {got:?}, expected {expected:?}"),
72 Self::InvalidNewNonceHash { got, expected }
73 => write!(f, "new nonce hash mismatch: got {got:?}, expected {expected:?}"),
74 }
75 }
76}
77
78pub struct Step1 { nonce: [u8; 16] }
82
83pub struct Step2 {
85 nonce: [u8; 16],
86 server_nonce: [u8; 16],
87 new_nonce: [u8; 32],
88}
89
90pub struct Step3 {
92 nonce: [u8; 16],
93 server_nonce: [u8; 16],
94 new_nonce: [u8; 32],
95 gab: BigUint,
96 time_offset: i32,
97}
98
99#[derive(Clone, Debug, PartialEq)]
101pub struct Finished {
102 pub auth_key: [u8; 256],
104 pub time_offset: i32,
106 pub first_salt: i64,
108}
109
110pub fn step1() -> Result<(layer_tl_types::functions::ReqPqMulti, Step1), Error> {
114 let mut buf = [0u8; 16];
115 getrandom::getrandom(&mut buf).expect("getrandom");
116 do_step1(&buf)
117}
118
119fn do_step1(random: &[u8; 16]) -> Result<(layer_tl_types::functions::ReqPqMulti, Step1), Error> {
120 let nonce = *random;
121 Ok((layer_tl_types::functions::ReqPqMulti { nonce }, Step1 { nonce }))
122}
123
124pub fn step2(
128 data: Step1,
129 response: layer_tl_types::enums::ResPq,
130) -> Result<(layer_tl_types::functions::ReqDhParams, Step2), Error> {
131 let mut rnd = [0u8; 256];
132 getrandom::getrandom(&mut rnd).expect("getrandom");
133 do_step2(data, response, &rnd)
134}
135
136fn do_step2(
137 data: Step1,
138 response: layer_tl_types::enums::ResPq,
139 random: &[u8; 256],
140) -> Result<(layer_tl_types::functions::ReqDhParams, Step2), Error> {
141 let Step1 { nonce } = data;
142
143 let layer_tl_types::enums::ResPq::ResPq(res_pq) = response;
145
146 check_nonce(&res_pq.nonce, &nonce)?;
147
148 if res_pq.pq.len() != 8 {
149 return Err(Error::InvalidPqSize { size: res_pq.pq.len() });
150 }
151
152 let pq = u64::from_be_bytes(res_pq.pq.as_slice().try_into().unwrap());
153 let (p, q) = factorize(pq);
154
155 let mut new_nonce = [0u8; 32];
156 new_nonce.copy_from_slice(&random[..32]);
157
158 let rnd224: &[u8; 224] = random[32..].try_into().unwrap();
160
161 fn trim_be(v: u64) -> Vec<u8> {
162 let b = v.to_be_bytes();
163 let skip = b.iter().position(|&x| x != 0).unwrap_or(7);
164 b[skip..].to_vec()
165 }
166
167 let p_bytes = trim_be(p);
168 let q_bytes = trim_be(q);
169
170 let pq_inner = layer_tl_types::enums::PQInnerData::PQInnerData(
173 layer_tl_types::types::PQInnerData {
174 pq: pq.to_be_bytes().to_vec(),
175 p: p_bytes.clone(),
176 q: q_bytes.clone(),
177 nonce,
178 server_nonce: res_pq.server_nonce,
179 new_nonce,
180 }
181 ).to_bytes();
182
183 let fingerprint = res_pq.server_public_key_fingerprints
184 .iter()
185 .copied()
186 .find(|&fp| key_for_fingerprint(fp).is_some())
187 .ok_or_else(|| Error::UnknownFingerprints {
188 fingerprints: res_pq.server_public_key_fingerprints.clone()
189 })?;
190
191 let key = key_for_fingerprint(fingerprint).unwrap();
192 let ciphertext = rsa::encrypt_hashed(&pq_inner, &key, rnd224);
193
194 Ok((
195 layer_tl_types::functions::ReqDhParams {
196 nonce,
197 server_nonce: res_pq.server_nonce,
198 p: p_bytes,
199 q: q_bytes,
200 public_key_fingerprint: fingerprint,
201 encrypted_data: ciphertext,
202 },
203 Step2 { nonce, server_nonce: res_pq.server_nonce, new_nonce },
204 ))
205}
206
207pub fn step3(
211 data: Step2,
212 response: layer_tl_types::enums::ServerDhParams,
213) -> Result<(layer_tl_types::functions::SetClientDhParams, Step3), Error> {
214 let mut rnd = [0u8; 272]; getrandom::getrandom(&mut rnd).expect("getrandom");
216 let now = SystemTime::now()
217 .duration_since(UNIX_EPOCH).unwrap().as_secs() as i32;
218 do_step3(data, response, &rnd, now)
219}
220
221fn do_step3(
222 data: Step2,
223 response: layer_tl_types::enums::ServerDhParams,
224 random: &[u8; 272],
225 now: i32,
226) -> Result<(layer_tl_types::functions::SetClientDhParams, Step3), Error> {
227 let Step2 { nonce, server_nonce, new_nonce } = data;
228
229 let mut server_dh_ok = match response {
230 layer_tl_types::enums::ServerDhParams::Fail(f) => {
231 check_nonce(&f.nonce, &nonce)?;
232 check_server_nonce(&f.server_nonce, &server_nonce)?;
233 let digest: [u8; 20] = {
235 let mut sha = Sha1::new();
236 sha.update(new_nonce);
237 sha.finalize().into()
238 };
239 let mut expected_hash = [0u8; 16];
240 expected_hash.copy_from_slice(&digest[4..]);
241 check_new_nonce_hash(&f.new_nonce_hash, &expected_hash)?;
242 return Err(Error::DhParamsFail);
243 }
244 layer_tl_types::enums::ServerDhParams::Ok(x) => x,
245 };
246
247 check_nonce(&server_dh_ok.nonce, &nonce)?;
248 check_server_nonce(&server_dh_ok.server_nonce, &server_nonce)?;
249
250 if server_dh_ok.encrypted_answer.len() % 16 != 0 {
251 return Err(Error::EncryptedResponseNotPadded { len: server_dh_ok.encrypted_answer.len() });
252 }
253
254 let (key, iv) = generate_key_data_from_nonce(&server_nonce, &new_nonce);
255 aes::ige_decrypt(&mut server_dh_ok.encrypted_answer, &key, &iv);
256 let plain = server_dh_ok.encrypted_answer;
257
258 let got_hash: [u8; 20] = plain[..20].try_into().unwrap();
259 let mut cursor = Cursor::from_slice(&plain[20..]);
260
261 let inner = match layer_tl_types::enums::ServerDhInnerData::deserialize(&mut cursor) {
264 Ok(layer_tl_types::enums::ServerDhInnerData::ServerDhInnerData(x)) => x,
265 Err(e) => return Err(Error::InvalidDhInnerData { error: e }),
266 };
267
268 let expected_hash: [u8; 20] = {
269 let mut sha = Sha1::new();
270 sha.update(&plain[20..20 + cursor.pos()]);
271 sha.finalize().into()
272 };
273 if got_hash != expected_hash {
274 return Err(Error::InvalidAnswerHash { got: got_hash, expected: expected_hash });
275 }
276
277 check_nonce(&inner.nonce, &nonce)?;
278 check_server_nonce(&inner.server_nonce, &server_nonce)?;
279
280 check_p_and_g(&inner.dh_prime, inner.g as u32)
282 .map_err(|source| Error::InvalidDhPrime { source })?;
283
284 let dh_prime = BigUint::from_bytes_be(&inner.dh_prime);
285 let g = inner.g.to_biguint().unwrap();
286 let g_a = BigUint::from_bytes_be(&inner.g_a);
287 let time_offset = inner.server_time - now;
288
289 let b = BigUint::from_bytes_be(&random[..256]);
290 let g_b = g.modpow(&b, &dh_prime);
291 let gab = g_a.modpow(&b, &dh_prime);
292
293 let one = BigUint::from(1u32);
295 check_g_in_range(&g, &one, &(&dh_prime - &one))?;
296 check_g_in_range(&g_a, &one, &(&dh_prime - &one))?;
297 check_g_in_range(&g_b, &one, &(&dh_prime - &one))?;
298 let safety = one.clone() << (2048 - 64);
299 check_g_in_range(&g_a, &safety, &(&dh_prime - &safety))?;
300 check_g_in_range(&g_b, &safety, &(&dh_prime - &safety))?;
301
302 let client_dh_inner = layer_tl_types::enums::ClientDhInnerData::ClientDhInnerData(
305 layer_tl_types::types::ClientDhInnerData {
306 nonce,
307 server_nonce,
308 retry_id: 0,
309 g_b: g_b.to_bytes_be(),
310 }
311 ).to_bytes();
312
313 let digest: [u8; 20] = {
314 let mut sha = Sha1::new();
315 sha.update(&client_dh_inner);
316 sha.finalize().into()
317 };
318
319 let pad_len = (16 - ((20 + client_dh_inner.len()) % 16)) % 16;
320 let rnd16 = &random[256..256 + pad_len.min(16)];
321
322 let mut hashed = Vec::with_capacity(20 + client_dh_inner.len() + pad_len);
323 hashed.extend_from_slice(&digest);
324 hashed.extend_from_slice(&client_dh_inner);
325 hashed.extend_from_slice(&rnd16[..pad_len]);
326
327 aes::ige_encrypt(&mut hashed, &key, &iv);
328
329 Ok((
330 layer_tl_types::functions::SetClientDhParams {
331 nonce,
332 server_nonce,
333 encrypted_data: hashed,
334 },
335 Step3 { nonce, server_nonce, new_nonce, gab, time_offset },
336 ))
337}
338
339pub fn finish(
343 data: Step3,
344 response: layer_tl_types::enums::SetClientDhParamsAnswer,
345) -> Result<Finished, Error> {
346 let Step3 { nonce, server_nonce, new_nonce, gab, time_offset } = data;
347
348 struct DhData { nonce: [u8; 16], server_nonce: [u8; 16], hash: [u8; 16], num: u8 }
349
350 let dh = match response {
351 layer_tl_types::enums::SetClientDhParamsAnswer::DhGenOk(x) =>
353 DhData { nonce: x.nonce, server_nonce: x.server_nonce, hash: x.new_nonce_hash1, num: 1 },
354 layer_tl_types::enums::SetClientDhParamsAnswer::DhGenRetry(x) =>
355 DhData { nonce: x.nonce, server_nonce: x.server_nonce, hash: x.new_nonce_hash2, num: 2 },
356 layer_tl_types::enums::SetClientDhParamsAnswer::DhGenFail(x) =>
357 DhData { nonce: x.nonce, server_nonce: x.server_nonce, hash: x.new_nonce_hash3, num: 3 },
358 };
359
360 check_nonce(&dh.nonce, &nonce)?;
361 check_server_nonce(&dh.server_nonce, &server_nonce)?;
362
363 let mut key_bytes = [0u8; 256];
364 let gab_bytes = gab.to_bytes_be();
365 let skip = 256 - gab_bytes.len();
366 key_bytes[skip..].copy_from_slice(&gab_bytes);
367
368 let auth_key = AuthKey::from_bytes(key_bytes);
369 let expected_hash = auth_key.calc_new_nonce_hash(&new_nonce, dh.num);
370 check_new_nonce_hash(&dh.hash, &expected_hash)?;
371
372 let first_salt = {
373 let mut buf = [0u8; 8];
374 for ((dst, a), b) in buf.iter_mut().zip(&new_nonce[..8]).zip(&server_nonce[..8]) {
375 *dst = a ^ b;
376 }
377 i64::from_le_bytes(buf)
378 };
379
380 match dh.num {
381 1 => Ok(Finished { auth_key: auth_key.to_bytes(), time_offset, first_salt }),
382 2 => Err(Error::DhGenRetry),
383 _ => Err(Error::DhGenFail),
384 }
385}
386
387fn check_nonce(got: &[u8; 16], expected: &[u8; 16]) -> Result<(), Error> {
390 if got == expected { Ok(()) } else {
391 Err(Error::InvalidNonce { got: *got, expected: *expected })
392 }
393}
394fn check_server_nonce(got: &[u8; 16], expected: &[u8; 16]) -> Result<(), Error> {
395 if got == expected { Ok(()) } else {
396 Err(Error::InvalidServerNonce { got: *got, expected: *expected })
397 }
398}
399fn check_new_nonce_hash(got: &[u8; 16], expected: &[u8; 16]) -> Result<(), Error> {
400 if got == expected { Ok(()) } else {
401 Err(Error::InvalidNewNonceHash { got: *got, expected: *expected })
402 }
403}
404fn check_g_in_range(val: &BigUint, lo: &BigUint, hi: &BigUint) -> Result<(), Error> {
405 if lo < val && val < hi { Ok(()) } else {
406 Err(Error::GParameterOutOfRange { value: val.clone(), low: lo.clone(), high: hi.clone() })
407 }
408}
409
410#[allow(clippy::unreadable_literal)]
412pub fn key_for_fingerprint(fp: i64) -> Option<rsa::Key> {
413 Some(match fp {
414 -3414540481677951611 => rsa::Key::new(
416 "29379598170669337022986177149456128565388431120058863768162556424047512191330847455146576344487764408661701890505066208632169112269581063774293102577308490531282748465986139880977280302242772832972539403531316010870401287642763009136156734339538042419388722777357134487746169093539093850251243897188928735903389451772730245253062963384108812842079887538976360465290946139638691491496062099570836476454855996319192747663615955633778034897140982517446405334423701359108810182097749467210509584293428076654573384828809574217079944388301239431309115013843331317877374435868468779972014486325557807783825502498215169806323",
417 "65537"
418 )?,
419 -5595554452916591101 => rsa::Key::new(
421 "25342889448840415564971689590713473206898847759084779052582026594546022463853940585885215951168491965708222649399180603818074200620463776135424884632162512403163793083921641631564740959529419359595852941166848940585952337613333022396096584117954892216031229237302943701877588456738335398602461675225081791820393153757504952636234951323237820036543581047826906120927972487366805292115792231423684261262330394324750785450942589751755390156647751460719351439969059949569615302809050721500330239005077889855323917509948255722081644689442127297605422579707142646660768825302832201908302295573257427896031830742328565032949",
422 "65537"
423 )?,
424 _ => return None,
425 })
426}