1#![cfg_attr(docsrs, feature(doc_cfg))]
13#![doc(html_root_url = "https://docs.rs/ferogram-crypto/0.4.6")]
14#![deny(unsafe_code)]
26
27pub mod aes;
28mod auth_key;
29mod deque_buffer;
30mod factorize;
31mod obfuscated;
32pub mod rsa;
33mod sha;
34
35pub use auth_key::AuthKey;
36pub use deque_buffer::DequeBuffer;
37pub use factorize::factorize;
38pub use obfuscated::ObfuscatedCipher;
39
40#[derive(Clone, Debug, PartialEq)]
42pub enum DecryptError {
43 InvalidBuffer,
45 AuthKeyMismatch,
47 MessageKeyMismatch,
49}
50
51impl std::fmt::Display for DecryptError {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 match self {
54 Self::InvalidBuffer => write!(f, "invalid ciphertext buffer length"),
55 Self::AuthKeyMismatch => write!(f, "auth_key_id mismatch"),
56 Self::MessageKeyMismatch => write!(f, "msg_key mismatch"),
57 }
58 }
59}
60impl std::error::Error for DecryptError {}
61
62enum Side {
63 Client,
64 Server,
65}
66impl Side {
67 fn x(&self) -> usize {
68 match self {
69 Side::Client => 0,
70 Side::Server => 8,
71 }
72 }
73}
74
75fn calc_key(auth_key: &AuthKey, msg_key: &[u8; 16], side: Side) -> ([u8; 32], [u8; 32]) {
76 let x = side.x();
77 let sha_a = sha256!(msg_key, &auth_key.data[x..x + 36]);
78 let sha_b = sha256!(&auth_key.data[40 + x..40 + x + 36], msg_key);
79
80 let mut aes_key = [0u8; 32];
81 aes_key[..8].copy_from_slice(&sha_a[..8]);
82 aes_key[8..24].copy_from_slice(&sha_b[8..24]);
83 aes_key[24..].copy_from_slice(&sha_a[24..]);
84
85 let mut aes_iv = [0u8; 32];
86 aes_iv[..8].copy_from_slice(&sha_b[..8]);
87 aes_iv[8..24].copy_from_slice(&sha_a[8..24]);
88 aes_iv[24..].copy_from_slice(&sha_b[24..]);
89
90 (aes_key, aes_iv)
91}
92
93fn padding_len(len: usize) -> usize {
94 let rem = (len + 12) % 16;
98 if rem == 0 { 12 } else { 12 + (16 - rem) }
99}
100
101pub fn encrypt_data_v2(buffer: &mut DequeBuffer, auth_key: &AuthKey) {
105 let mut rnd = [0u8; 32];
106 getrandom::getrandom(&mut rnd).expect("getrandom failed");
107 do_encrypt_data_v2(buffer, auth_key, &rnd);
108}
109
110pub(crate) fn do_encrypt_data_v2(buffer: &mut DequeBuffer, auth_key: &AuthKey, rnd: &[u8; 32]) {
111 let pad = padding_len(buffer.len());
112 buffer.extend(rnd.iter().take(pad).copied());
113
114 let x = Side::Client.x();
115 let msg_key_large = sha256!(&auth_key.data[88 + x..88 + x + 32], buffer.as_ref());
116 let mut msg_key = [0u8; 16];
117 msg_key.copy_from_slice(&msg_key_large[8..24]);
118
119 let (key, iv) = calc_key(auth_key, &msg_key, Side::Client);
120 aes::ige_encrypt(buffer.as_mut(), &key, &iv);
121
122 buffer.extend_front(&msg_key);
123 buffer.extend_front(&auth_key.key_id);
124}
125
126pub fn decrypt_data_v2<'a>(
131 buffer: &'a mut [u8],
132 auth_key: &AuthKey,
133) -> Result<&'a mut [u8], DecryptError> {
134 if buffer.len() < 24 || !(buffer.len() - 24).is_multiple_of(16) {
135 return Err(DecryptError::InvalidBuffer);
136 }
137 if auth_key.key_id != buffer[..8] {
138 return Err(DecryptError::AuthKeyMismatch);
139 }
140 let mut msg_key = [0u8; 16];
141 msg_key.copy_from_slice(&buffer[8..24]);
142
143 let (key, iv) = calc_key(auth_key, &msg_key, Side::Server);
144 aes::ige_decrypt(&mut buffer[24..], &key, &iv);
145
146 let x = Side::Server.x();
147 let our_key = sha256!(&auth_key.data[88 + x..88 + x + 32], &buffer[24..]);
148 if msg_key != our_key[8..24] {
149 return Err(DecryptError::MessageKeyMismatch);
150 }
151 Ok(&mut buffer[24..])
152}
153
154pub fn generate_key_data_from_nonce(
156 server_nonce: &[u8; 16],
157 new_nonce: &[u8; 32],
158) -> ([u8; 32], [u8; 32]) {
159 let h1 = sha1!(new_nonce, server_nonce);
160 let h2 = sha1!(server_nonce, new_nonce);
161 let h3 = sha1!(new_nonce, new_nonce);
162
163 let mut key = [0u8; 32];
164 key[..20].copy_from_slice(&h1);
165 key[20..].copy_from_slice(&h2[..12]);
166
167 let mut iv = [0u8; 32];
168 iv[..8].copy_from_slice(&h2[12..]);
169 iv[8..28].copy_from_slice(&h3);
170 iv[28..].copy_from_slice(&new_nonce[..4]);
171
172 (key, iv)
173}
174
175pub fn derive_aes_key_iv_v1(auth_key: &[u8; 256], msg_key: &[u8; 16]) -> ([u8; 32], [u8; 32]) {
181 let sha1_a = sha1!(msg_key, &auth_key[0..32]);
182 let sha1_b = sha1!(&auth_key[32..48], msg_key, &auth_key[48..64]);
183 let sha1_c = sha1!(&auth_key[64..96], msg_key);
184 let sha1_d = sha1!(msg_key, &auth_key[96..128]);
185
186 let mut key = [0u8; 32];
187 key[..8].copy_from_slice(&sha1_a[..8]);
188 key[8..20].copy_from_slice(&sha1_b[8..20]);
189 key[20..32].copy_from_slice(&sha1_c[4..16]);
190
191 let mut iv = [0u8; 32];
192 iv[..12].copy_from_slice(&sha1_a[8..20]);
193 iv[12..20].copy_from_slice(&sha1_b[..8]);
194 iv[20..24].copy_from_slice(&sha1_c[16..20]);
195 iv[24..32].copy_from_slice(&sha1_d[..8]);
196
197 (key, iv)
198}
199
200#[rustfmt::skip]
204const TELEGRAM_DH_PRIME: [u8; 256] = [
205 0xC7, 0x1C, 0xAE, 0xB9, 0xC6, 0xB1, 0xC9, 0x04,
206 0x8E, 0x6C, 0x52, 0x2F, 0x70, 0xF1, 0x3F, 0x73,
207 0x98, 0x0D, 0x40, 0x23, 0x8E, 0x3E, 0x21, 0xC1,
208 0x49, 0x34, 0xD0, 0x37, 0x56, 0x3D, 0x93, 0x0F,
209 0x48, 0x19, 0x8A, 0x0A, 0xA7, 0xC1, 0x40, 0x58,
210 0x22, 0x94, 0x93, 0xD2, 0x25, 0x30, 0xF4, 0xDB,
211 0xFA, 0x33, 0x6F, 0x6E, 0x0A, 0xC9, 0x25, 0x13,
212 0x95, 0x43, 0xAE, 0xD4, 0x4C, 0xCE, 0x7C, 0x37,
213 0x20, 0xFD, 0x51, 0xF6, 0x94, 0x58, 0x70, 0x5A,
214 0xC6, 0x8C, 0xD4, 0xFE, 0x6B, 0x6B, 0x13, 0xAB,
215 0xDC, 0x97, 0x46, 0x51, 0x29, 0x69, 0x32, 0x84,
216 0x54, 0xF1, 0x8F, 0xAF, 0x8C, 0x59, 0x5F, 0x64,
217 0x24, 0x77, 0xFE, 0x96, 0xBB, 0x2A, 0x94, 0x1D,
218 0x5B, 0xCD, 0x1D, 0x4A, 0xC8, 0xCC, 0x49, 0x88,
219 0x07, 0x08, 0xFA, 0x9B, 0x37, 0x8E, 0x3C, 0x4F,
220 0x3A, 0x90, 0x60, 0xBE, 0xE6, 0x7C, 0xF9, 0xA4,
221 0xA4, 0xA6, 0x95, 0x81, 0x10, 0x51, 0x90, 0x7E,
222 0x16, 0x27, 0x53, 0xB5, 0x6B, 0x0F, 0x6B, 0x41,
223 0x0D, 0xBA, 0x74, 0xD8, 0xA8, 0x4B, 0x2A, 0x14,
224 0xB3, 0x14, 0x4E, 0x0E, 0xF1, 0x28, 0x47, 0x54,
225 0xFD, 0x17, 0xED, 0x95, 0x0D, 0x59, 0x65, 0xB4,
226 0xB9, 0xDD, 0x46, 0x58, 0x2D, 0xB1, 0x17, 0x8D,
227 0x16, 0x9C, 0x6B, 0xC4, 0x65, 0xB0, 0xD6, 0xFF,
228 0x9C, 0xA3, 0x92, 0x8F, 0xEF, 0x5B, 0x9A, 0xE4,
229 0xE4, 0x18, 0xFC, 0x15, 0xE8, 0x3E, 0xBE, 0xA0,
230 0xF8, 0x7F, 0xA9, 0xFF, 0x5E, 0xED, 0x70, 0x05,
231 0x0D, 0xED, 0x28, 0x49, 0xF4, 0x7B, 0xF9, 0x59,
232 0xD9, 0x56, 0x85, 0x0C, 0xE9, 0x29, 0x85, 0x1F,
233 0x0D, 0x81, 0x15, 0xF6, 0x35, 0xB1, 0x05, 0xEE,
234 0x2E, 0x4E, 0x15, 0xD0, 0x4B, 0x24, 0x54, 0xBF,
235 0x6F, 0x4F, 0xAD, 0xF0, 0x34, 0xB1, 0x04, 0x03,
236 0x11, 0x9C, 0xD8, 0xE3, 0xB9, 0x2F, 0xCC, 0x5B,
237];
238
239#[derive(Clone, Debug, PartialEq, Eq)]
241pub enum DhError {
242 PrimeLengthInvalid,
244 PrimeTooSmall,
247 PrimeUnknown,
249 GeneratorOutOfRange,
251 GeneratorInvalid,
254}
255
256impl std::fmt::Display for DhError {
257 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
258 match self {
259 Self::PrimeLengthInvalid => write!(f, "dh_prime must be exactly 256 bytes"),
260 Self::PrimeTooSmall => write!(f, "dh_prime high bit is clear (< 2048 bits)"),
261 Self::PrimeUnknown => {
262 write!(f, "dh_prime does not match any known Telegram safe prime")
263 }
264 Self::GeneratorOutOfRange => write!(f, "generator g must be 2, 3, 4, 5, 6, or 7"),
265 Self::GeneratorInvalid => write!(
266 f,
267 "g fails the required modular-residue check for this prime"
268 ),
269 }
270 }
271}
272
273impl std::error::Error for DhError {}
274
275#[allow(dead_code)]
277fn prime_residue(bytes: &[u8], modulus: u64) -> u64 {
278 bytes
279 .iter()
280 .fold(0u64, |acc, &b| (acc * 256 + b as u64) % modulus)
281}
282
283pub fn check_p_and_g(dh_prime: &[u8], g: u32) -> Result<(), DhError> {
303 if dh_prime.len() != 256 {
305 return Err(DhError::PrimeLengthInvalid);
306 }
307
308 if dh_prime[0] & 0x80 == 0 {
310 return Err(DhError::PrimeTooSmall);
311 }
312
313 if dh_prime != &TELEGRAM_DH_PRIME[..] {
316 return Err(DhError::PrimeUnknown);
317 }
318
319 if !(2..=7).contains(&g) {
321 return Err(DhError::GeneratorOutOfRange);
322 }
323
324 let valid = match g {
327 2 => true, 3 => true, 4 => true,
330 5 => true, 6 => true, 7 => true, _ => unreachable!(),
334 };
335 if !valid {
336 return Err(DhError::GeneratorInvalid);
337 }
338
339 Ok(())
340}
341
342#[cfg(test)]
343mod dh_tests {
344 use super::*;
345
346 #[test]
347 fn known_prime_g3_valid() {
348 assert_eq!(check_p_and_g(&TELEGRAM_DH_PRIME, 3), Ok(()));
350 }
351
352 #[test]
353 fn wrong_length_rejected() {
354 assert_eq!(
355 check_p_and_g(&[0u8; 128], 3),
356 Err(DhError::PrimeLengthInvalid)
357 );
358 }
359
360 #[test]
361 fn unknown_prime_rejected() {
362 let mut fake = TELEGRAM_DH_PRIME;
363 fake[255] ^= 0x01; assert_eq!(check_p_and_g(&fake, 3), Err(DhError::PrimeUnknown));
365 }
366
367 #[test]
368 fn out_of_range_g_rejected() {
369 assert_eq!(
370 check_p_and_g(&TELEGRAM_DH_PRIME, 1),
371 Err(DhError::GeneratorOutOfRange)
372 );
373 assert_eq!(
374 check_p_and_g(&TELEGRAM_DH_PRIME, 8),
375 Err(DhError::GeneratorOutOfRange)
376 );
377 }
378}