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