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