layer_mtproto/
encrypted.rs1use std::time::{SystemTime, UNIX_EPOCH};
8
9use layer_crypto::{AuthKey, DequeBuffer, decrypt_data_v2, encrypt_data_v2};
10use layer_tl_types::RemoteCall;
11
12
13#[derive(Debug)]
15pub enum DecryptError {
16 Crypto(layer_crypto::DecryptError),
18 FrameTooShort,
20 SessionMismatch,
22}
23
24impl std::fmt::Display for DecryptError {
25 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26 match self {
27 Self::Crypto(e) => write!(f, "crypto: {e}"),
28 Self::FrameTooShort => write!(f, "inner plaintext too short"),
29 Self::SessionMismatch => write!(f, "session_id mismatch"),
30 }
31 }
32}
33impl std::error::Error for DecryptError {}
34
35pub struct DecryptedMessage {
37 pub salt: i64,
39 pub session_id: i64,
41 pub msg_id: i64,
43 pub seq_no: i32,
45 pub body: Vec<u8>,
47}
48
49pub struct EncryptedSession {
56 auth_key: AuthKey,
57 session_id: i64,
58 sequence: i32,
59 last_msg_id: i64,
60 pub salt: i64,
62 pub time_offset: i32,
64}
65
66impl EncryptedSession {
67 pub fn new(auth_key: [u8; 256], first_salt: i64, time_offset: i32) -> Self {
69 let mut rnd = [0u8; 8];
70 getrandom::getrandom(&mut rnd).expect("getrandom");
71 Self {
72 auth_key: AuthKey::from_bytes(auth_key),
73 session_id: i64::from_le_bytes(rnd),
74 sequence: 0,
75 last_msg_id: 0,
76 salt: first_salt,
77 time_offset,
78 }
79 }
80
81 fn next_msg_id(&mut self) -> i64 {
83 let now = SystemTime::now()
84 .duration_since(UNIX_EPOCH).unwrap();
85 let secs = (now.as_secs() as i32).wrapping_add(self.time_offset) as u64;
86 let nanos = now.subsec_nanos() as u64;
87 let mut id = ((secs << 32) | (nanos << 2)) as i64;
88 if self.last_msg_id >= id { id = self.last_msg_id + 4; }
89 self.last_msg_id = id;
90 id
91 }
92
93 fn next_seq_no(&mut self) -> i32 {
96 let n = self.sequence * 2 + 1;
97 self.sequence += 1;
98 n
99 }
100
101 pub fn next_seq_no_ncr(&self) -> i32 {
108 self.sequence * 2
109 }
110
111 pub fn correct_seq_no(&mut self, code: u32) {
118 match code {
119 32 => {
120 self.sequence += 64;
122 log::debug!("[layer] G-03 seq_no correction: code 32, bumped seq to {}", self.sequence);
123 }
124 33 => {
125 self.sequence = self.sequence.saturating_sub(16).max(1);
130 log::debug!("[layer] G-03 seq_no correction: code 33, lowered seq to {}", self.sequence);
131 }
132 _ => {}
133 }
134 }
135
136 pub fn correct_time_offset(&mut self, server_msg_id: i64) {
145 let server_time = (server_msg_id >> 32) as i32;
147 let local_now = SystemTime::now()
148 .duration_since(UNIX_EPOCH).unwrap()
149 .as_secs() as i32;
150 let new_offset = server_time.wrapping_sub(local_now);
151 log::debug!(
152 "[layer] G-12 time_offset correction: {} → {} (server_time={server_time})",
153 self.time_offset, new_offset
154 );
155 self.time_offset = new_offset;
156 self.last_msg_id = 0;
158 }
159
160 pub fn alloc_msg_seqno(&mut self, content_related: bool) -> (i64, i32) {
170 let msg_id = self.next_msg_id();
171 let seqno = if content_related { self.next_seq_no() } else { self.next_seq_no_ncr() };
172 (msg_id, seqno)
173 }
174
175 pub fn pack_body_with_msg_id(&mut self, body: &[u8], content_related: bool) -> (Vec<u8>, i64) {
183 let msg_id = self.next_msg_id();
184 let seq_no = if content_related { self.next_seq_no() } else { self.next_seq_no_ncr() };
185
186 let inner_len = 8 + 8 + 8 + 4 + 4 + body.len();
187 let mut buf = DequeBuffer::with_capacity(inner_len, 32);
188 buf.extend(self.salt.to_le_bytes());
189 buf.extend(self.session_id.to_le_bytes());
190 buf.extend(msg_id.to_le_bytes());
191 buf.extend(seq_no.to_le_bytes());
192 buf.extend((body.len() as u32).to_le_bytes());
193 buf.extend(body.iter().copied());
194
195 encrypt_data_v2(&mut buf, &self.auth_key);
196 (buf.as_ref().to_vec(), msg_id)
197 }
198
199 pub fn pack_container(&mut self, container_body: &[u8]) -> Vec<u8> {
205 let (wire, _msg_id) = self.pack_body_with_msg_id(container_body, false);
206 wire
207 }
208
209 pub fn pack_serializable<S: layer_tl_types::Serializable>(&mut self, call: &S) -> Vec<u8> {
213 let body = call.to_bytes();
214 let msg_id = self.next_msg_id();
215 let seq_no = self.next_seq_no();
216
217 let inner_len = 8 + 8 + 8 + 4 + 4 + body.len();
218 let mut buf = DequeBuffer::with_capacity(inner_len, 32);
219 buf.extend(self.salt.to_le_bytes());
220 buf.extend(self.session_id.to_le_bytes());
221 buf.extend(msg_id.to_le_bytes());
222 buf.extend(seq_no.to_le_bytes());
223 buf.extend((body.len() as u32).to_le_bytes());
224 buf.extend(body.iter().copied());
225
226 encrypt_data_v2(&mut buf, &self.auth_key);
227 buf.as_ref().to_vec()
228 }
229
230 pub fn pack_serializable_with_msg_id<S: layer_tl_types::Serializable>(&mut self, call: &S) -> (Vec<u8>, i64) {
232 let body = call.to_bytes();
233 let msg_id = self.next_msg_id();
234 let seq_no = self.next_seq_no();
235 let inner_len = 8 + 8 + 8 + 4 + 4 + body.len();
236 let mut buf = DequeBuffer::with_capacity(inner_len, 32);
237 buf.extend(self.salt.to_le_bytes());
238 buf.extend(self.session_id.to_le_bytes());
239 buf.extend(msg_id.to_le_bytes());
240 buf.extend(seq_no.to_le_bytes());
241 buf.extend((body.len() as u32).to_le_bytes());
242 buf.extend(body.iter().copied());
243 encrypt_data_v2(&mut buf, &self.auth_key);
244 (buf.as_ref().to_vec(), msg_id)
245 }
246
247 pub fn pack_with_msg_id<R: RemoteCall>(&mut self, call: &R) -> (Vec<u8>, i64) {
249 let body = call.to_bytes();
250 let msg_id = self.next_msg_id();
251 let seq_no = self.next_seq_no();
252 let inner_len = 8 + 8 + 8 + 4 + 4 + body.len();
253 let mut buf = DequeBuffer::with_capacity(inner_len, 32);
254 buf.extend(self.salt.to_le_bytes());
255 buf.extend(self.session_id.to_le_bytes());
256 buf.extend(msg_id.to_le_bytes());
257 buf.extend(seq_no.to_le_bytes());
258 buf.extend((body.len() as u32).to_le_bytes());
259 buf.extend(body.iter().copied());
260 encrypt_data_v2(&mut buf, &self.auth_key);
261 (buf.as_ref().to_vec(), msg_id)
262 }
263
264 pub fn pack<R: RemoteCall>(&mut self, call: &R) -> Vec<u8> {
266 let body = call.to_bytes();
267 let msg_id = self.next_msg_id();
268 let seq_no = self.next_seq_no();
269
270 let inner_len = 8 + 8 + 8 + 4 + 4 + body.len();
271 let mut buf = DequeBuffer::with_capacity(inner_len, 32);
272 buf.extend(self.salt.to_le_bytes());
273 buf.extend(self.session_id.to_le_bytes());
274 buf.extend(msg_id.to_le_bytes());
275 buf.extend(seq_no.to_le_bytes());
276 buf.extend((body.len() as u32).to_le_bytes());
277 buf.extend(body.iter().copied());
278
279 encrypt_data_v2(&mut buf, &self.auth_key);
280 buf.as_ref().to_vec()
281 }
282
283 pub fn unpack(&self, frame: &mut [u8]) -> Result<DecryptedMessage, DecryptError> {
285 let plaintext = decrypt_data_v2(frame, &self.auth_key)
286 .map_err(DecryptError::Crypto)?;
287
288 if plaintext.len() < 32 {
289 return Err(DecryptError::FrameTooShort);
290 }
291
292 let salt = i64::from_le_bytes(plaintext[..8].try_into().unwrap());
293 let session_id = i64::from_le_bytes(plaintext[8..16].try_into().unwrap());
294 let msg_id = i64::from_le_bytes(plaintext[16..24].try_into().unwrap());
295 let seq_no = i32::from_le_bytes(plaintext[24..28].try_into().unwrap());
296 let body_len = u32::from_le_bytes(plaintext[28..32].try_into().unwrap()) as usize;
297
298 if session_id != self.session_id {
299 return Err(DecryptError::SessionMismatch);
300 }
301
302 let body = plaintext[32..32 + body_len.min(plaintext.len() - 32)].to_vec();
303
304 Ok(DecryptedMessage { salt, session_id, msg_id, seq_no, body })
305 }
306
307 pub fn auth_key_bytes(&self) -> [u8; 256] { self.auth_key.to_bytes() }
309
310 pub fn session_id(&self) -> i64 { self.session_id }
312}
313
314impl EncryptedSession {
315 pub fn decrypt_frame(
318 auth_key: &[u8; 256],
319 session_id: i64,
320 frame: &mut [u8],
321 ) -> Result<DecryptedMessage, DecryptError> {
322 let key = AuthKey::from_bytes(*auth_key);
323 let plaintext = decrypt_data_v2(frame, &key)
324 .map_err(DecryptError::Crypto)?;
325 if plaintext.len() < 32 {
326 return Err(DecryptError::FrameTooShort);
327 }
328 let salt = i64::from_le_bytes(plaintext[..8].try_into().unwrap());
329 let sid = i64::from_le_bytes(plaintext[8..16].try_into().unwrap());
330 let msg_id = i64::from_le_bytes(plaintext[16..24].try_into().unwrap());
331 let seq_no = i32::from_le_bytes(plaintext[24..28].try_into().unwrap());
332 let body_len = u32::from_le_bytes(plaintext[28..32].try_into().unwrap()) as usize;
333 if sid != session_id {
334 return Err(DecryptError::SessionMismatch);
335 }
336 let body = plaintext[32..32 + body_len.min(plaintext.len() - 32)].to_vec();
337 Ok(DecryptedMessage { salt, session_id: sid, msg_id, seq_no, body })
338 }
339}