1#![cfg_attr(docsrs, feature(doc_cfg))]
14#![doc(html_root_url = "https://docs.rs/ferogram-crypto/0.6.3")]
15#![deny(unsafe_code)]
75
76pub mod aes;
77mod auth_key;
78mod deque_buffer;
79pub mod dh;
80mod factorize;
81mod obfuscated;
82pub mod rsa;
83mod sha;
84pub mod srp;
85
86pub use auth_key::AuthKey;
87pub use deque_buffer::DequeBuffer;
88pub use factorize::factorize;
89pub use obfuscated::{ObfuscatedCipher, build_fake_tls_keys, build_obfuscated_init};
90
91pub fn fill_random(buf: &mut [u8]) {
95 getrandom::getrandom(buf).expect("OS RNG unavailable");
96}
97
98#[derive(Clone, Debug, PartialEq)]
100pub enum DecryptError {
101 InvalidBuffer,
103 AuthKeyMismatch,
105 MessageKeyMismatch,
107}
108
109impl std::fmt::Display for DecryptError {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 match self {
112 Self::InvalidBuffer => write!(f, "invalid ciphertext buffer length"),
113 Self::AuthKeyMismatch => write!(f, "auth_key_id mismatch"),
114 Self::MessageKeyMismatch => write!(f, "msg_key mismatch"),
115 }
116 }
117}
118impl std::error::Error for DecryptError {}
119
120enum Side {
121 Client,
122 Server,
123}
124impl Side {
125 fn x(&self) -> usize {
126 match self {
127 Side::Client => 0,
128 Side::Server => 8,
129 }
130 }
131}
132
133fn calc_key(auth_key: &AuthKey, msg_key: &[u8; 16], side: Side) -> ([u8; 32], [u8; 32]) {
134 let x = side.x();
135 let sha_a = sha256!(msg_key, &auth_key.data[x..x + 36]);
136 let sha_b = sha256!(&auth_key.data[40 + x..40 + x + 36], msg_key);
137
138 let mut aes_key = [0u8; 32];
139 aes_key[..8].copy_from_slice(&sha_a[..8]);
140 aes_key[8..24].copy_from_slice(&sha_b[8..24]);
141 aes_key[24..].copy_from_slice(&sha_a[24..]);
142
143 let mut aes_iv = [0u8; 32];
144 aes_iv[..8].copy_from_slice(&sha_b[..8]);
145 aes_iv[8..24].copy_from_slice(&sha_a[8..24]);
146 aes_iv[24..].copy_from_slice(&sha_b[24..]);
147
148 (aes_key, aes_iv)
149}
150
151fn padding_len(len: usize) -> usize {
152 let rem = (len + 12) % 16;
156 if rem == 0 { 12 } else { 12 + (16 - rem) }
157}
158
159pub fn encrypt_data_v2(buffer: &mut DequeBuffer, auth_key: &AuthKey) {
163 let mut rnd = [0u8; 32];
164 getrandom::getrandom(&mut rnd).expect("getrandom failed");
165 do_encrypt_data_v2(buffer, auth_key, &rnd);
166}
167
168pub(crate) fn do_encrypt_data_v2(buffer: &mut DequeBuffer, auth_key: &AuthKey, rnd: &[u8; 32]) {
169 let pad = padding_len(buffer.len());
170 buffer.extend(rnd.iter().take(pad).copied());
171
172 let x = Side::Client.x();
173 let msg_key_large = sha256!(&auth_key.data[88 + x..88 + x + 32], buffer.as_ref());
174 let mut msg_key = [0u8; 16];
175 msg_key.copy_from_slice(&msg_key_large[8..24]);
176
177 let (key, iv) = calc_key(auth_key, &msg_key, Side::Client);
178 aes::ige_encrypt(buffer.as_mut(), &key, &iv);
179
180 buffer.extend_front(&msg_key);
181 buffer.extend_front(&auth_key.key_id);
182}
183
184pub fn decrypt_data_v2<'a>(
189 buffer: &'a mut [u8],
190 auth_key: &AuthKey,
191) -> Result<&'a mut [u8], DecryptError> {
192 let frame_len = buffer.len();
194 let frame_hex: String = buffer
195 .iter()
196 .take(32)
197 .map(|b| format!("{b:02x}"))
198 .collect::<Vec<_>>()
199 .join(" ");
200
201 if buffer.len() < 24 || !(buffer.len() - 24).is_multiple_of(16) {
202 tracing::warn!(
205 frame_len,
206 first_bytes = %frame_hex,
207 "decrypt failed: frame too short or not block-aligned \
208 (need >= 24 bytes and (len-24) % 16 == 0)"
209 );
210 return Err(DecryptError::InvalidBuffer);
211 }
212
213 let our_key_id = auth_key.key_id();
214 let frame_key_id = &buffer[..8];
215 if our_key_id != frame_key_id {
216 let our_hex = our_key_id
221 .iter()
222 .map(|b| format!("{b:02x}"))
223 .collect::<Vec<_>>()
224 .join("");
225 let frame_hex_id = frame_key_id
226 .iter()
227 .map(|b| format!("{b:02x}"))
228 .collect::<Vec<_>>()
229 .join("");
230 tracing::warn!(
231 frame_len,
232 our_key_id = %our_hex,
233 frame_key_id = %frame_hex_id,
234 first_bytes = %frame_hex,
235 "decrypt failed: auth_key_id mismatch (stale session or wrong DC key)"
236 );
237 return Err(DecryptError::AuthKeyMismatch);
238 }
239 let mut msg_key = [0u8; 16];
240 msg_key.copy_from_slice(&buffer[8..24]);
241
242 let (key, iv) = calc_key(auth_key, &msg_key, Side::Server);
243 aes::ige_decrypt(&mut buffer[24..], &key, &iv);
244
245 let x = Side::Server.x();
246 let our_key = sha256!(&auth_key.data[88 + x..88 + x + 32], &buffer[24..]);
247 if msg_key != our_key[8..24] {
248 return Err(DecryptError::MessageKeyMismatch);
249 }
250 Ok(&mut buffer[24..])
251}
252
253pub fn generate_key_data_from_nonce(
255 server_nonce: &[u8; 16],
256 new_nonce: &[u8; 32],
257) -> ([u8; 32], [u8; 32]) {
258 let h1 = sha1!(new_nonce, server_nonce);
259 let h2 = sha1!(server_nonce, new_nonce);
260 let h3 = sha1!(new_nonce, new_nonce);
261
262 let mut key = [0u8; 32];
263 key[..20].copy_from_slice(&h1);
264 key[20..].copy_from_slice(&h2[..12]);
265
266 let mut iv = [0u8; 32];
267 iv[..8].copy_from_slice(&h2[12..]);
268 iv[8..28].copy_from_slice(&h3);
269 iv[28..].copy_from_slice(&new_nonce[..4]);
270
271 (key, iv)
272}
273
274pub fn derive_aes_key_iv_v1(auth_key: &[u8; 256], msg_key: &[u8; 16]) -> ([u8; 32], [u8; 32]) {
280 let sha1_a = sha1!(msg_key, &auth_key[0..32]);
281 let sha1_b = sha1!(&auth_key[32..48], msg_key, &auth_key[48..64]);
282 let sha1_c = sha1!(&auth_key[64..96], msg_key);
283 let sha1_d = sha1!(msg_key, &auth_key[96..128]);
284
285 let mut key = [0u8; 32];
286 key[..8].copy_from_slice(&sha1_a[..8]);
287 key[8..20].copy_from_slice(&sha1_b[8..20]);
288 key[20..32].copy_from_slice(&sha1_c[4..16]);
289
290 let mut iv = [0u8; 32];
291 iv[..12].copy_from_slice(&sha1_a[8..20]);
292 iv[12..20].copy_from_slice(&sha1_b[..8]);
293 iv[20..24].copy_from_slice(&sha1_c[16..20]);
294 iv[24..32].copy_from_slice(&sha1_d[..8]);
295
296 (key, iv)
297}
298
299#[rustfmt::skip]
303const TELEGRAM_DH_PRIME: [u8; 256] = [
304 0xC7, 0x1C, 0xAE, 0xB9, 0xC6, 0xB1, 0xC9, 0x04,
305 0x8E, 0x6C, 0x52, 0x2F, 0x70, 0xF1, 0x3F, 0x73,
306 0x98, 0x0D, 0x40, 0x23, 0x8E, 0x3E, 0x21, 0xC1,
307 0x49, 0x34, 0xD0, 0x37, 0x56, 0x3D, 0x93, 0x0F,
308 0x48, 0x19, 0x8A, 0x0A, 0xA7, 0xC1, 0x40, 0x58,
309 0x22, 0x94, 0x93, 0xD2, 0x25, 0x30, 0xF4, 0xDB,
310 0xFA, 0x33, 0x6F, 0x6E, 0x0A, 0xC9, 0x25, 0x13,
311 0x95, 0x43, 0xAE, 0xD4, 0x4C, 0xCE, 0x7C, 0x37,
312 0x20, 0xFD, 0x51, 0xF6, 0x94, 0x58, 0x70, 0x5A,
313 0xC6, 0x8C, 0xD4, 0xFE, 0x6B, 0x6B, 0x13, 0xAB,
314 0xDC, 0x97, 0x46, 0x51, 0x29, 0x69, 0x32, 0x84,
315 0x54, 0xF1, 0x8F, 0xAF, 0x8C, 0x59, 0x5F, 0x64,
316 0x24, 0x77, 0xFE, 0x96, 0xBB, 0x2A, 0x94, 0x1D,
317 0x5B, 0xCD, 0x1D, 0x4A, 0xC8, 0xCC, 0x49, 0x88,
318 0x07, 0x08, 0xFA, 0x9B, 0x37, 0x8E, 0x3C, 0x4F,
319 0x3A, 0x90, 0x60, 0xBE, 0xE6, 0x7C, 0xF9, 0xA4,
320 0xA4, 0xA6, 0x95, 0x81, 0x10, 0x51, 0x90, 0x7E,
321 0x16, 0x27, 0x53, 0xB5, 0x6B, 0x0F, 0x6B, 0x41,
322 0x0D, 0xBA, 0x74, 0xD8, 0xA8, 0x4B, 0x2A, 0x14,
323 0xB3, 0x14, 0x4E, 0x0E, 0xF1, 0x28, 0x47, 0x54,
324 0xFD, 0x17, 0xED, 0x95, 0x0D, 0x59, 0x65, 0xB4,
325 0xB9, 0xDD, 0x46, 0x58, 0x2D, 0xB1, 0x17, 0x8D,
326 0x16, 0x9C, 0x6B, 0xC4, 0x65, 0xB0, 0xD6, 0xFF,
327 0x9C, 0xA3, 0x92, 0x8F, 0xEF, 0x5B, 0x9A, 0xE4,
328 0xE4, 0x18, 0xFC, 0x15, 0xE8, 0x3E, 0xBE, 0xA0,
329 0xF8, 0x7F, 0xA9, 0xFF, 0x5E, 0xED, 0x70, 0x05,
330 0x0D, 0xED, 0x28, 0x49, 0xF4, 0x7B, 0xF9, 0x59,
331 0xD9, 0x56, 0x85, 0x0C, 0xE9, 0x29, 0x85, 0x1F,
332 0x0D, 0x81, 0x15, 0xF6, 0x35, 0xB1, 0x05, 0xEE,
333 0x2E, 0x4E, 0x15, 0xD0, 0x4B, 0x24, 0x54, 0xBF,
334 0x6F, 0x4F, 0xAD, 0xF0, 0x34, 0xB1, 0x04, 0x03,
335 0x11, 0x9C, 0xD8, 0xE3, 0xB9, 0x2F, 0xCC, 0x5B,
336];
337
338#[derive(Clone, Debug, PartialEq, Eq)]
340pub enum DhError {
341 PrimeLengthInvalid,
343 PrimeTooSmall,
346 PrimeUnknown,
348 GeneratorOutOfRange,
350 GeneratorInvalid,
353}
354
355impl std::fmt::Display for DhError {
356 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
357 match self {
358 Self::PrimeLengthInvalid => write!(f, "dh_prime must be exactly 256 bytes"),
359 Self::PrimeTooSmall => write!(f, "dh_prime high bit is clear (< 2048 bits)"),
360 Self::PrimeUnknown => {
361 write!(f, "dh_prime does not match any known Telegram safe prime")
362 }
363 Self::GeneratorOutOfRange => write!(f, "generator g must be 2, 3, 4, 5, 6, or 7"),
364 Self::GeneratorInvalid => write!(
365 f,
366 "g fails the required modular-residue check for this prime"
367 ),
368 }
369 }
370}
371
372impl std::error::Error for DhError {}
373
374fn prime_residue(bytes: &[u8], modulus: u64) -> u64 {
376 bytes
377 .iter()
378 .fold(0u64, |acc, &b| (acc * 256 + b as u64) % modulus)
379}
380
381pub fn check_p_and_g(dh_prime: &[u8], g: u32) -> Result<(), DhError> {
401 if dh_prime.len() != 256 {
403 return Err(DhError::PrimeLengthInvalid);
404 }
405
406 if dh_prime[0] & 0x80 == 0 {
408 return Err(DhError::PrimeTooSmall);
409 }
410
411 if dh_prime != &TELEGRAM_DH_PRIME[..] {
414 return Err(DhError::PrimeUnknown);
415 }
416
417 if !(2..=7).contains(&g) {
419 return Err(DhError::GeneratorOutOfRange);
420 }
421
422 let valid = match g {
424 2 => prime_residue(dh_prime, 8) == 7,
425 3 => prime_residue(dh_prime, 3) == 2,
426 4 => true,
427 5 => {
428 let r = prime_residue(dh_prime, 5);
429 r == 1 || r == 4
430 }
431 6 => {
432 let r = prime_residue(dh_prime, 24);
433 r == 19 || r == 23
434 }
435 7 => {
436 let r = prime_residue(dh_prime, 7);
437 r == 3 || r == 5 || r == 6
438 }
439 _ => unreachable!(),
440 };
441 if !valid {
442 return Err(DhError::GeneratorInvalid);
443 }
444
445 Ok(())
446}
447
448#[cfg(test)]
449mod dh_tests {
450 use super::*;
451
452 #[test]
453 fn known_prime_g3_valid() {
454 assert_eq!(check_p_and_g(&TELEGRAM_DH_PRIME, 3), Ok(()));
456 }
457
458 #[test]
459 fn wrong_length_rejected() {
460 assert_eq!(
461 check_p_and_g(&[0u8; 128], 3),
462 Err(DhError::PrimeLengthInvalid)
463 );
464 }
465
466 #[test]
467 fn unknown_prime_rejected() {
468 let mut fake = TELEGRAM_DH_PRIME;
469 fake[255] ^= 0x01; assert_eq!(check_p_and_g(&fake, 3), Err(DhError::PrimeUnknown));
471 }
472
473 #[test]
474 fn out_of_range_g_rejected() {
475 assert_eq!(
476 check_p_and_g(&TELEGRAM_DH_PRIME, 1),
477 Err(DhError::GeneratorOutOfRange)
478 );
479 assert_eq!(
480 check_p_and_g(&TELEGRAM_DH_PRIME, 8),
481 Err(DhError::GeneratorOutOfRange)
482 );
483 }
484}