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