1use std::{fmt, io};
11
12use ::sha1::{Digest as _, Sha1};
13use aes::Aes256;
14use ctr::cipher::{KeyIvInit as _, StreamCipher as _};
15use hmac::{KeyInit as _, Mac as _};
16use sha2::{Sha256, Sha512};
17
18use crate::{Error, Result};
19
20pub const AES_BLOCK_SIZE: usize = 16;
22
23pub const AES_KEY_SIZE: usize = 32;
25
26pub const MSG_KEY_SIZE: usize = 16;
28
29const LENGTH_HEADER_SIZE: usize = 4;
31
32#[derive(Clone)]
36pub struct AuthKey([u8; AuthKey::SIZE]);
37
38impl AuthKey {
39 pub const SIZE: usize = 256;
41
42 #[must_use]
44 pub const fn new(bytes: [u8; Self::SIZE]) -> Self {
45 Self(bytes)
46 }
47
48 pub fn from_slice(bytes: &[u8]) -> Result<Self> {
53 let key = <[u8; Self::SIZE]>::try_from(bytes).map_err(|_| Error::BadLength {
54 what: "auth key",
55 expected: Self::SIZE,
56 actual: bytes.len(),
57 })?;
58 Ok(Self(key))
59 }
60
61 #[must_use]
63 pub const fn as_bytes(&self) -> &[u8; Self::SIZE] {
64 &self.0
65 }
66
67 #[must_use]
69 pub fn key_id(&self) -> u64 {
70 let hash = Sha1::digest(self.0);
71 let mut id = [0u8; 8];
72 id.copy_from_slice(&hash[12..20]);
73 u64::from_le_bytes(id)
74 }
75}
76
77impl fmt::Debug for AuthKey {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 f.debug_struct("AuthKey")
80 .field("key_id", &format_args!("{:#018x}", self.key_id()))
81 .finish_non_exhaustive()
82 }
83}
84
85#[must_use]
90pub fn prepare_aes_oldmtp(
91 auth_key: &AuthKey,
92 msg_key: &[u8; MSG_KEY_SIZE],
93 send: bool,
94) -> ([u8; AES_KEY_SIZE], [u8; AES_KEY_SIZE]) {
95 let x = if send { 0 } else { 8 };
96 let key = auth_key.as_bytes();
97
98 let sha1_a = Sha1::new()
99 .chain_update(msg_key)
100 .chain_update(&key[x..x + 32])
101 .finalize();
102 let sha1_b = Sha1::new()
103 .chain_update(&key[x + 32..x + 48])
104 .chain_update(msg_key)
105 .chain_update(&key[x + 48..x + 64])
106 .finalize();
107 let sha1_c = Sha1::new()
108 .chain_update(&key[x + 64..x + 96])
109 .chain_update(msg_key)
110 .finalize();
111 let sha1_d = Sha1::new()
112 .chain_update(msg_key)
113 .chain_update(&key[x + 96..x + 128])
114 .finalize();
115
116 let mut aes_key = [0u8; AES_KEY_SIZE];
117 aes_key[..8].copy_from_slice(&sha1_a[..8]);
118 aes_key[8..20].copy_from_slice(&sha1_b[8..20]);
119 aes_key[20..].copy_from_slice(&sha1_c[4..16]);
120
121 let mut aes_iv = [0u8; AES_KEY_SIZE];
122 aes_iv[..12].copy_from_slice(&sha1_a[8..20]);
123 aes_iv[12..20].copy_from_slice(&sha1_b[..8]);
124 aes_iv[20..24].copy_from_slice(&sha1_c[16..20]);
125 aes_iv[24..].copy_from_slice(&sha1_d[..8]);
126
127 (aes_key, aes_iv)
128}
129
130fn ige_params<'k>(
132 buf: &[u8],
133 key: &'k [u8],
134 iv: &'k [u8],
135) -> Result<(&'k [u8; AES_KEY_SIZE], &'k [u8; AES_KEY_SIZE])> {
136 if !buf.len().is_multiple_of(AES_BLOCK_SIZE) {
137 return Err(Error::BadLength {
138 what: "AES-IGE buffer",
139 expected: buf.len().next_multiple_of(AES_BLOCK_SIZE),
140 actual: buf.len(),
141 });
142 }
143 let key = <&[u8; AES_KEY_SIZE]>::try_from(key).map_err(|_| Error::BadLength {
144 what: "AES-IGE key",
145 expected: AES_KEY_SIZE,
146 actual: key.len(),
147 })?;
148 let iv = <&[u8; AES_KEY_SIZE]>::try_from(iv).map_err(|_| Error::BadLength {
149 what: "AES-IGE iv",
150 expected: AES_KEY_SIZE,
151 actual: iv.len(),
152 })?;
153 Ok((key, iv))
154}
155
156pub fn aes_ige_encrypt(buf: &mut [u8], key: &[u8], iv: &[u8]) -> Result<()> {
162 let (key, iv) = ige_params(buf, key, iv)?;
163 grammers_crypto::aes::ige_encrypt(buf, key, iv);
164 Ok(())
165}
166
167pub fn aes_ige_decrypt(buf: &mut [u8], key: &[u8], iv: &[u8]) -> Result<()> {
173 let (key, iv) = ige_params(buf, key, iv)?;
174 grammers_crypto::aes::ige_decrypt(buf, key, iv);
175 Ok(())
176}
177
178#[must_use]
180pub const fn local_padding_len(data_len: usize) -> usize {
181 let size = data_len + LENGTH_HEADER_SIZE;
182 size.next_multiple_of(AES_BLOCK_SIZE) - size
183}
184
185pub fn encrypt_local(
197 data: &[u8],
198 local_key: &AuthKey,
199 padding_source: impl FnOnce(usize) -> Vec<u8>,
200) -> Result<Vec<u8>> {
201 let size = data.len() + LENGTH_HEADER_SIZE;
202 let real_len = u32::try_from(size).map_err(|_| Error::BadLength {
203 what: "local data",
204 expected: usize::try_from(u32::MAX).unwrap_or(usize::MAX),
205 actual: size,
206 })?;
207 let padding_len = local_padding_len(data.len());
208 let padding = padding_source(padding_len);
209 if padding.len() != padding_len {
210 return Err(Error::BadLength {
211 what: "local padding",
212 expected: padding_len,
213 actual: padding.len(),
214 });
215 }
216
217 let mut out = Vec::with_capacity(MSG_KEY_SIZE + size + padding_len);
218 out.extend_from_slice(&[0u8; MSG_KEY_SIZE]);
219 out.extend_from_slice(&real_len.to_le_bytes());
220 out.extend_from_slice(data);
221 out.extend_from_slice(&padding);
222
223 let (head, body) = out.split_at_mut(MSG_KEY_SIZE);
224 let mut msg_key = [0u8; MSG_KEY_SIZE];
225 msg_key.copy_from_slice(&Sha1::digest(&*body)[..MSG_KEY_SIZE]);
226 head.copy_from_slice(&msg_key);
227
228 let (aes_key, aes_iv) = prepare_aes_oldmtp(local_key, &msg_key, false);
229 aes_ige_encrypt(body, &aes_key, &aes_iv)?;
230 Ok(out)
231}
232
233pub fn encrypt_local_random(data: &[u8], local_key: &AuthKey) -> Result<Vec<u8>> {
240 let mut padding = vec![0u8; local_padding_len(data.len())];
241 random_fill(&mut padding)?;
242 encrypt_local(data, local_key, move |_| padding)
243}
244
245pub fn decrypt_local(encrypted: &[u8], local_key: &AuthKey) -> Result<Vec<u8>> {
256 let encrypted_size = encrypted.len();
257 if encrypted_size <= AES_BLOCK_SIZE || !encrypted_size.is_multiple_of(AES_BLOCK_SIZE) {
258 return Err(Error::BadEncryptedDataSize {
259 size: encrypted_size,
260 });
261 }
262
263 let mut msg_key = [0u8; MSG_KEY_SIZE];
264 msg_key.copy_from_slice(&encrypted[..MSG_KEY_SIZE]);
265 let mut decrypted = encrypted[MSG_KEY_SIZE..].to_vec();
266
267 let (aes_key, aes_iv) = prepare_aes_oldmtp(local_key, &msg_key, false);
268 aes_ige_decrypt(&mut decrypted, &aes_key, &aes_iv)?;
269 if Sha1::digest(&decrypted)[..MSG_KEY_SIZE] != msg_key {
270 return Err(Error::BadDecryptKey);
271 }
272
273 let full_len = encrypted_size - MSG_KEY_SIZE;
274 let bad_size = Error::BadDecryptedDataSize {
275 encrypted_size,
276 full_len,
277 decrypted_size: decrypted.len(),
278 };
279 let mut header = [0u8; LENGTH_HEADER_SIZE];
280 header.copy_from_slice(&decrypted[..LENGTH_HEADER_SIZE]);
281 let Ok(data_len) = usize::try_from(u32::from_le_bytes(header)) else {
282 return Err(bad_size);
283 };
284 if data_len > decrypted.len()
285 || data_len <= full_len - AES_BLOCK_SIZE
286 || data_len < LENGTH_HEADER_SIZE
287 {
288 return Err(bad_size);
289 }
290
291 decrypted.truncate(data_len);
292 decrypted.drain(..LENGTH_HEADER_SIZE);
293 Ok(decrypted)
294}
295
296pub const AES_CTR_IV_SIZE: usize = 16;
298
299pub const PQ_MAX_SIZE: usize = 8;
301
302const SHA256_BLOCK_SIZE: usize = 64;
304
305#[must_use]
307pub fn sha1(data: &[u8]) -> [u8; 20] {
308 Sha1::digest(data).into()
309}
310
311#[must_use]
313pub fn sha256(data: &[u8]) -> [u8; 32] {
314 Sha256::digest(data).into()
315}
316
317#[must_use]
319pub fn hmac_sha256(key: &[u8], data: &[u8]) -> [u8; 32] {
320 let mut block = hmac::digest::Key::<hmac::Hmac<Sha256>>::default();
323 if key.len() > SHA256_BLOCK_SIZE {
324 block[..32].copy_from_slice(&Sha256::digest(key));
325 } else {
326 block[..key.len()].copy_from_slice(key);
327 }
328 let mut mac = hmac::Hmac::<Sha256>::new(&block);
329 mac.update(data);
330 mac.finalize().into_bytes().into()
331}
332
333#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
335pub enum Digest {
336 Sha1,
338 Sha256,
340 Sha512,
342}
343
344impl Digest {
345 pub fn from_name(name: &str) -> Result<Self> {
350 [
351 ("sha1", Self::Sha1),
352 ("sha256", Self::Sha256),
353 ("sha512", Self::Sha512),
354 ]
355 .into_iter()
356 .find_map(|(known, digest)| name.eq_ignore_ascii_case(known).then_some(digest))
357 .ok_or_else(|| Error::InvalidInput {
358 what: "PBKDF2 digest",
359 reason: format!("unknown digest {name:?}"),
360 })
361 }
362}
363
364pub fn pbkdf2(
370 password: &[u8],
371 salt: &[u8],
372 iterations: u32,
373 key_len: usize,
374 digest: Digest,
375) -> Result<Vec<u8>> {
376 if iterations == 0 {
377 return Err(Error::InvalidInput {
378 what: "PBKDF2 iterations",
379 reason: "needs at least one iteration".to_owned(),
380 });
381 }
382 let mut key = vec![0u8; key_len];
383 match digest {
384 Digest::Sha1 => ::pbkdf2::pbkdf2_hmac::<Sha1>(password, salt, iterations, &mut key),
385 Digest::Sha256 => ::pbkdf2::pbkdf2_hmac::<Sha256>(password, salt, iterations, &mut key),
386 Digest::Sha512 => ::pbkdf2::pbkdf2_hmac::<Sha512>(password, salt, iterations, &mut key),
387 }
388 Ok(key)
389}
390
391pub struct AesCtr(ctr::Ctr128BE<Aes256>);
398
399impl AesCtr {
400 pub fn new(key: &[u8], iv: &[u8]) -> Result<Self> {
405 let key = <[u8; AES_KEY_SIZE]>::try_from(key).map_err(|_| Error::BadLength {
406 what: "AES-CTR key",
407 expected: AES_KEY_SIZE,
408 actual: key.len(),
409 })?;
410 let iv = <[u8; AES_CTR_IV_SIZE]>::try_from(iv).map_err(|_| Error::BadLength {
411 what: "AES-CTR iv",
412 expected: AES_CTR_IV_SIZE,
413 actual: iv.len(),
414 })?;
415 Ok(Self(ctr::Ctr128BE::<Aes256>::new(&key.into(), &iv.into())))
416 }
417
418 pub fn apply(&mut self, buf: &mut [u8]) {
420 self.0.apply_keystream(buf);
421 }
422}
423
424impl fmt::Debug for AesCtr {
425 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
426 f.debug_struct("AesCtr").finish_non_exhaustive()
427 }
428}
429
430pub fn factorize_pq(pq: &[u8]) -> Result<(Vec<u8>, Vec<u8>)> {
442 if pq.is_empty() || pq.len() > PQ_MAX_SIZE {
443 return Err(Error::BadLength {
444 what: "pq",
445 expected: PQ_MAX_SIZE,
446 actual: pq.len(),
447 });
448 }
449 let mut be = [0u8; PQ_MAX_SIZE];
450 be[PQ_MAX_SIZE - pq.len()..].copy_from_slice(pq);
451 let n = u64::from_be_bytes(be);
452 let factor = find_factor(n).ok_or_else(|| Error::InvalidInput {
453 what: "pq",
454 reason: format!("{n} is not a product of two factors greater than 1"),
455 })?;
456 let (p, q) = (factor.min(n / factor), factor.max(n / factor));
457 Ok((minimal_be(p), minimal_be(q)))
458}
459
460fn minimal_be(value: u64) -> Vec<u8> {
462 let bytes = value.to_be_bytes();
463 let skip = bytes.iter().take_while(|&&b| b == 0).count();
464 bytes[skip..].to_vec()
465}
466
467fn find_factor(n: u64) -> Option<u64> {
470 if n < 4 {
471 return None;
472 }
473 if n.is_multiple_of(2) {
474 return Some(2);
475 }
476 if is_prime(n) {
477 return None;
478 }
479 (1..u64::MAX).find_map(|c| pollard_brent(n, c))
482}
483
484fn mul_mod(a: u64, b: u64, m: u64) -> u64 {
486 let product = u128::from(a) * u128::from(b) % u128::from(m);
487 u64::try_from(product).unwrap_or_default()
489}
490
491fn pow_mod(mut base: u64, mut exp: u64, m: u64) -> u64 {
493 let mut result = 1 % m;
494 base %= m;
495 while exp > 0 {
496 if exp & 1 == 1 {
497 result = mul_mod(result, base, m);
498 }
499 base = mul_mod(base, base, m);
500 exp >>= 1;
501 }
502 result
503}
504
505fn is_prime(n: u64) -> bool {
508 const BASES: [u64; 12] = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37];
509 let s = (n - 1).trailing_zeros();
510 let d = (n - 1) >> s;
511 BASES.iter().all(|&a| {
512 if a % n == 0 {
513 return true;
514 }
515 let mut x = pow_mod(a, d, n);
516 if x == 1 || x == n - 1 {
517 return true;
518 }
519 for _ in 1..s {
520 x = mul_mod(x, x, n);
521 if x == n - 1 {
522 return true;
523 }
524 }
525 false
526 })
527}
528
529fn gcd(mut a: u64, mut b: u64) -> u64 {
531 while b != 0 {
532 (a, b) = (b, a % b);
533 }
534 a
535}
536
537fn pollard_brent(n: u64, increment: u64) -> Option<u64> {
540 const BATCH: u64 = 128;
541 let step = |value: u64| {
542 let sum = u128::from(mul_mod(value, value, n)) + u128::from(increment);
543 u64::try_from(sum % u128::from(n)).unwrap_or_default()
544 };
545 let (mut anchor, mut walker, mut batch_start) = (2u64, 2u64, 2u64);
546 let (mut divisor, mut product, mut span) = (1u64, 1u64, 1u64);
547 while divisor == 1 {
548 anchor = walker;
549 for _ in 0..span {
550 walker = step(walker);
551 }
552 let mut done = 0;
553 while done < span && divisor == 1 {
554 batch_start = walker;
555 for _ in 0..BATCH.min(span - done) {
556 walker = step(walker);
557 product = mul_mod(product, anchor.abs_diff(walker), n);
558 }
559 divisor = gcd(product, n);
560 done += BATCH;
561 }
562 span = span.saturating_mul(2);
563 }
564 if divisor == n {
565 loop {
567 batch_start = step(batch_start);
568 divisor = gcd(anchor.abs_diff(batch_start), n);
569 if divisor > 1 {
570 break;
571 }
572 }
573 }
574 (divisor != n).then_some(divisor)
575}
576
577pub fn random_fill(buf: &mut [u8]) -> Result<()> {
582 getrandom::fill(buf).map_err(|e| Error::Io(io::Error::other(e)))
583}