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