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