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 {
95 let n = self.sequence * 2 + 1;
96 self.sequence += 1;
97 n
98 }
99
100 pub fn pack_serializable<S: layer_tl_types::Serializable>(&mut self, call: &S) -> Vec<u8> {
115 let body = call.to_bytes();
116 let msg_id = self.next_msg_id();
117 let seq_no = self.next_seq_no();
118
119 let inner_len = 8 + 8 + 8 + 4 + 4 + body.len();
120 let mut buf = DequeBuffer::with_capacity(inner_len, 32);
121 buf.extend(self.salt.to_le_bytes());
122 buf.extend(self.session_id.to_le_bytes());
123 buf.extend(msg_id.to_le_bytes());
124 buf.extend(seq_no.to_le_bytes());
125 buf.extend((body.len() as u32).to_le_bytes());
126 buf.extend(body.iter().copied());
127
128 encrypt_data_v2(&mut buf, &self.auth_key);
129 buf.as_ref().to_vec()
130 }
131
132 pub fn pack<R: RemoteCall>(&mut self, call: &R) -> Vec<u8> {
136 let body = call.to_bytes();
137 let msg_id = self.next_msg_id();
138 let seq_no = self.next_seq_no();
139
140 let inner_len = 8 + 8 + 8 + 4 + 4 + body.len();
142 let mut buf = DequeBuffer::with_capacity(inner_len, 32);
144 buf.extend(self.salt.to_le_bytes());
145 buf.extend(self.session_id.to_le_bytes());
146 buf.extend(msg_id.to_le_bytes());
147 buf.extend(seq_no.to_le_bytes());
148 buf.extend((body.len() as u32).to_le_bytes());
149 buf.extend(body.iter().copied());
150
151 encrypt_data_v2(&mut buf, &self.auth_key);
152 buf.as_ref().to_vec()
153 }
154
155 pub fn unpack(&self, frame: &mut Vec<u8>) -> Result<DecryptedMessage, DecryptError> {
160 let plaintext = decrypt_data_v2(frame, &self.auth_key)
161 .map_err(DecryptError::Crypto)?;
162
163 if plaintext.len() < 32 {
165 return Err(DecryptError::FrameTooShort);
166 }
167
168 let salt = i64::from_le_bytes(plaintext[..8].try_into().unwrap());
169 let session_id = i64::from_le_bytes(plaintext[8..16].try_into().unwrap());
170 let msg_id = i64::from_le_bytes(plaintext[16..24].try_into().unwrap());
171 let seq_no = i32::from_le_bytes(plaintext[24..28].try_into().unwrap());
172 let body_len = u32::from_le_bytes(plaintext[28..32].try_into().unwrap()) as usize;
173
174 if session_id != self.session_id {
175 return Err(DecryptError::SessionMismatch);
176 }
177
178 let body = plaintext[32..32 + body_len.min(plaintext.len() - 32)].to_vec();
179
180 Ok(DecryptedMessage { salt, session_id, msg_id, seq_no, body })
181 }
182
183 pub fn auth_key_bytes(&self) -> [u8; 256] { self.auth_key.to_bytes() }
185
186 pub fn session_id(&self) -> i64 { self.session_id }
188}