1use bytes::BytesMut;
4use openssl::memcmp;
5use openssl::rand::rand_bytes;
6use std::convert::TryInto;
7use std::io;
8use tokio_util::codec::Decoder;
9use tokio_util::codec::Encoder;
10
11use crate::voice::Clientbound;
12use crate::voice::Serverbound;
13use crate::voice::VoiceCodec;
14use crate::voice::VoicePacket;
15use crate::voice::VoicePacketDst;
16
17pub const MAX_PACKET_SIZE: usize = 1024;
21pub const KEY_SIZE: usize = 16;
23pub const BLOCK_SIZE: usize = std::mem::size_of::<u128>();
25
26pub struct CryptState<EncodeDst: VoicePacketDst, DecodeDst: VoicePacketDst> {
37 codec: VoiceCodec<EncodeDst, DecodeDst>,
38
39 key: [u8; KEY_SIZE],
40 encrypt_nonce: u128,
42 decrypt_nonce: u128,
43 decrypt_history: [u8; 0x100],
44
45 good: u32,
46 late: u32,
47 lost: u32,
48}
49pub type ServerCryptState = CryptState<Clientbound, Serverbound>;
51pub type ClientCryptState = CryptState<Serverbound, Clientbound>;
53
54#[derive(Clone, Copy, Debug, PartialEq, Eq)]
56pub enum DecryptError {
57 Eof,
59 Repeat,
61 Late,
63 Mac,
67}
68
69impl<EncodeDst: VoicePacketDst, DecodeDst: VoicePacketDst> CryptState<EncodeDst, DecodeDst> {
70 pub fn generate_new() -> Self {
72 let mut key = [0; KEY_SIZE];
73 rand_bytes(&mut key).unwrap();
74
75 CryptState {
76 codec: VoiceCodec::new(),
77
78 key,
79 encrypt_nonce: 0,
80 decrypt_nonce: 1 << 127,
81 decrypt_history: [0; 0x100],
82
83 good: 0,
84 late: 0,
85 lost: 0,
86 }
87 }
88
89 pub fn new_from(
91 key: [u8; KEY_SIZE],
92 encrypt_nonce: [u8; BLOCK_SIZE],
93 decrypt_nonce: [u8; BLOCK_SIZE],
94 ) -> Self {
95 CryptState {
96 codec: VoiceCodec::new(),
97
98 key,
99 encrypt_nonce: u128::from_le_bytes(encrypt_nonce),
100 decrypt_nonce: u128::from_le_bytes(decrypt_nonce),
101 decrypt_history: [0; 0x100],
102
103 good: 0,
104 late: 0,
105 lost: 0,
106 }
107 }
108
109 pub fn get_good(&self) -> u32 {
111 self.good
112 }
113
114 pub fn get_late(&self) -> u32 {
116 self.late
117 }
118
119 pub fn get_lost(&self) -> u32 {
121 self.lost
122 }
123
124 pub fn get_key(&self) -> &[u8; KEY_SIZE] {
126 &self.key
127 }
128
129 pub fn get_encrypt_nonce(&self) -> [u8; BLOCK_SIZE] {
131 self.encrypt_nonce.to_le_bytes()
132 }
133
134 pub fn get_decrypt_nonce(&self) -> [u8; BLOCK_SIZE] {
136 self.decrypt_nonce.to_le_bytes()
137 }
138
139 pub fn set_decrypt_nonce(&mut self, nonce: &[u8; BLOCK_SIZE]) {
141 self.decrypt_nonce = u128::from_le_bytes(*nonce);
142 }
143
144 pub fn encrypt(&mut self, packet: VoicePacket<EncodeDst>, dst: &mut BytesMut) {
146 self.encrypt_nonce = self.encrypt_nonce.wrapping_add(1);
147
148 dst.resize(4, 0);
150 let mut inner = dst.split_off(4);
151
152 self.codec
153 .encode(packet, &mut inner)
154 .expect("VoiceEncoder is infallible");
155
156 let tag = self.ocb_encrypt(inner.as_mut());
157 dst.unsplit(inner);
158
159 dst[0] = self.encrypt_nonce as u8;
160 dst[1..4].copy_from_slice(&tag.to_be_bytes()[0..3]);
161 }
162
163 pub fn decrypt(
165 &mut self,
166 buf: &mut BytesMut,
167 ) -> Result<Result<VoicePacket<DecodeDst>, io::Error>, DecryptError> {
168 if buf.len() < 4 {
169 return Err(DecryptError::Eof);
170 }
171 let header = buf.split_to(4);
172 let nonce_0 = header[0];
173
174 let saved_nonce = self.decrypt_nonce;
177 let mut late = false; let mut lost = 0; if self.decrypt_nonce.wrapping_add(1) as u8 == nonce_0 {
181 self.decrypt_nonce = self.decrypt_nonce.wrapping_add(1);
183 } else {
184 let diff = nonce_0.wrapping_sub(self.decrypt_nonce as u8) as i8;
186 self.decrypt_nonce = self.decrypt_nonce.wrapping_add(diff as u128);
187 if diff > 0 {
188 lost = i32::from(diff - 1); } else if diff > -30 {
190 if self.decrypt_history[nonce_0 as usize] == (self.decrypt_nonce >> 8) as u8 {
191 self.decrypt_nonce = saved_nonce;
192 return Err(DecryptError::Repeat);
193 }
194 late = true;
196 lost = -1;
197 } else {
198 return Err(DecryptError::Late); }
200 }
201
202 let tag = self.ocb_decrypt(buf.as_mut());
203 if !memcmp::eq(&tag.to_be_bytes()[0..3], &header[1..4]) {
204 self.decrypt_nonce = saved_nonce;
205 return Err(DecryptError::Mac);
206 }
207
208 self.decrypt_history[nonce_0 as usize] = (self.decrypt_nonce >> 8) as u8;
209
210 self.good += 1;
211 if late {
212 self.late += 1;
213 self.decrypt_nonce = saved_nonce;
214 }
215 self.lost = (self.lost as i32 + lost as i32) as u32;
216
217 Ok(self
218 .codec
219 .decode(buf)
220 .map(|it| it.expect("VoiceCodec is stateless")))
221 }
222
223 fn ocb_encrypt(&self, mut buf: &mut [u8]) -> u128 {
225 let mut offset = self.aes_encrypt(self.encrypt_nonce.to_be());
226 let mut checksum = 0u128;
227
228 while buf.len() > BLOCK_SIZE {
229 let (chunk, remainder) = buf.split_at_mut(BLOCK_SIZE);
230 buf = remainder;
231 let chunk: &mut [u8; BLOCK_SIZE] = chunk.try_into().expect("split_at works");
232
233 offset = s2(offset);
234
235 let plain = u128::from_be_bytes(*chunk);
236 let encrypted = self.aes_encrypt(offset ^ plain) ^ offset;
237 chunk.copy_from_slice(&encrypted.to_be_bytes());
238
239 checksum ^= plain;
240 }
241
242 offset = s2(offset);
243
244 let len = buf.len();
245 assert!(len <= BLOCK_SIZE);
246 let pad = self.aes_encrypt((len * 8) as u128 ^ offset);
247 let mut block = pad.to_be_bytes();
248 block[..len].copy_from_slice(buf);
249 let plain = u128::from_be_bytes(block);
250 let encrypted = pad ^ plain;
251 buf.copy_from_slice(&encrypted.to_be_bytes()[..len]);
252
253 checksum ^= plain;
254
255 self.aes_encrypt(offset ^ s2(offset) ^ checksum)
256 }
257
258 fn ocb_decrypt(&self, mut buf: &mut [u8]) -> u128 {
261 let mut offset = self.aes_encrypt(self.decrypt_nonce.to_be());
262 let mut checksum = 0u128;
263
264 while buf.len() > BLOCK_SIZE {
265 let (chunk, remainder) = buf.split_at_mut(BLOCK_SIZE);
266 buf = remainder;
267 let chunk: &mut [u8; BLOCK_SIZE] = chunk.try_into().expect("split_at works");
268
269 offset = s2(offset);
270
271 let encrypted = u128::from_be_bytes(*chunk);
272 let plain = self.aes_decrypt(offset ^ encrypted) ^ offset;
273 chunk.copy_from_slice(&plain.to_be_bytes());
274
275 checksum ^= plain;
276 }
277
278 offset = s2(offset);
279
280 let len = buf.len();
281 assert!(len <= BLOCK_SIZE);
282 let pad = self.aes_encrypt((len * 8) as u128 ^ offset);
283 let mut block = [0; BLOCK_SIZE];
284 block[..len].copy_from_slice(buf);
285 let plain = u128::from_be_bytes(block) ^ pad;
286 buf.copy_from_slice(&plain.to_be_bytes()[..len]);
287
288 checksum ^= plain;
289
290 self.aes_encrypt(offset ^ s2(offset) ^ checksum)
291 }
292
293 fn aes_encrypt(&self, block: u128) -> u128 {
295 let mut result = [0u8; BLOCK_SIZE * 2];
297 let mut crypter = openssl::symm::Crypter::new(
298 openssl::symm::Cipher::aes_128_ecb(),
299 openssl::symm::Mode::Encrypt,
300 &self.key,
301 None,
302 )
303 .unwrap();
304 crypter.pad(false);
305 crypter.update(&block.to_be_bytes(), &mut result).unwrap();
306 crypter.finalize(&mut result).unwrap();
307 u128::from_be_bytes((&result[..BLOCK_SIZE]).try_into().unwrap())
308 }
309
310 fn aes_decrypt(&self, block: u128) -> u128 {
312 let mut result = [0u8; BLOCK_SIZE * 2];
313 let mut crypter = openssl::symm::Crypter::new(
314 openssl::symm::Cipher::aes_128_ecb(),
315 openssl::symm::Mode::Decrypt,
316 &self.key,
317 None,
318 )
319 .unwrap();
320 crypter.pad(false);
321 crypter.update(&block.to_be_bytes(), &mut result).unwrap();
322 crypter.finalize(&mut result).unwrap();
323 u128::from_be_bytes((&result[..BLOCK_SIZE]).try_into().unwrap())
324 }
325}
326
327fn s2(block: u128) -> u128 {
328 let rot = block.rotate_left(1);
329 let carry = rot & 1;
330 rot ^ (carry * 0x86)
331}
332
333impl<EncodeDst: VoicePacketDst, DecodeDst: VoicePacketDst> Decoder
334 for CryptState<EncodeDst, DecodeDst>
335{
336 type Item = VoicePacket<DecodeDst>;
337 type Error = io::Error;
338
339 fn decode(&mut self, buf_mut: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
340 if buf_mut.is_empty() {
341 return Ok(None);
342 }
343 self.decrypt(buf_mut)
344 .unwrap_or_else(|_| {
345 Err(io::Error::new(
346 io::ErrorKind::InvalidData,
347 "failed to decrypt",
348 ))
349 })
350 .map(Some)
351 }
352}
353
354impl<EncodeDst: VoicePacketDst, DecodeDst: VoicePacketDst> Encoder<VoicePacket<EncodeDst>>
355 for CryptState<EncodeDst, DecodeDst>
356{
357 type Error = io::Error; fn encode(
360 &mut self,
361 item: VoicePacket<EncodeDst>,
362 dst: &mut BytesMut,
363 ) -> Result<(), Self::Error> {
364 self.encrypt(item, dst);
365 Ok(())
366 }
367}
368
369#[cfg(test)]
370mod test {
371 use bytes::BufMut;
372
373 use super::*;
374 use crate::voice::VoicePacketPayload;
375
376 fn u128hex(src: &str) -> u128 {
377 u128::from_str_radix(src, 16).unwrap()
378 }
379
380 fn bytes_from_hex(src: &str) -> BytesMut {
381 let mut buf = BytesMut::new();
382 hex_to_bytes(src, &mut buf);
383 buf
384 }
385
386 fn hex_to_bytes(src: &str, dst: &mut BytesMut) {
387 dst.clear();
388 dst.reserve(src.len() / 2);
389 let mut iter = src.chars();
390 while !iter.as_str().is_empty() {
391 dst.put_u8(u8::from_str_radix(&iter.as_str()[..2], 16).unwrap());
392 iter.next();
393 iter.next();
394 }
395 }
396
397 #[test]
398 fn aes_test_vectors() {
399 let key = u128hex("E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FA");
400 let state =
401 ClientCryptState::new_from(key.to_be_bytes(), Default::default(), Default::default());
402 assert_eq!(
403 u128hex("6743C3D1519AB4F2CD9A78AB09A511BD"),
404 state.aes_encrypt(u128hex("014BAF2278A69D331D5180103643E99A"))
405 );
406 assert_eq!(
407 u128hex("014BAF2278A69D331D5180103643E99A"),
408 state.aes_decrypt(u128hex("6743C3D1519AB4F2CD9A78AB09A511BD"))
409 );
410 }
411
412 #[test]
415 #[allow(clippy::cognitive_complexity)] fn ocb_test_vectors() {
417 macro_rules! test_cases {
418 ($(
419 T : $name:expr,
420 M : $plain:expr,
421 C : $cipher:expr,
422 T : $tag:expr,
423 )*) => {$(
424 let key = u128hex("000102030405060708090a0b0c0d0e0f");
425 let nonce = u128hex("000102030405060708090a0b0c0d0e0f");
426 let state = ClientCryptState::new_from(
427 key.to_be_bytes(),
428 nonce.to_be_bytes(),
429 nonce.to_be_bytes(),
430 );
431
432 let mut result = BytesMut::new();
433 hex_to_bytes($plain.as_ref(), &mut result);
434 let tag = state.ocb_encrypt(&mut result);
435 assert_eq!(bytes_from_hex($cipher), result, concat!("ENCRYPT-RESULT-", $name));
436 assert_eq!(u128hex($tag), tag, concat!("ENCRYPT-TAG-", $name));
437
438 hex_to_bytes($cipher.as_ref(), &mut result);
439 let tag = state.ocb_decrypt(&mut result);
440 assert_eq!(bytes_from_hex($plain), result, concat!("DECRYPT-RESULT-", $name));
441 assert_eq!(u128hex($tag), tag, concat!("DECRYPT-TAG-", $name));
442 )*};
443 }
444
445 test_cases! {
446 T : "OCB-AES-128-0B",
447 M : "",
448 C : "",
449 T : "BF3108130773AD5EC70EC69E7875A7B0",
450
451 T : "OCB-AES-128-8B",
452 M : "0001020304050607",
453 C : "C636B3A868F429BB",
454 T : "A45F5FDEA5C088D1D7C8BE37CABC8C5C",
455
456 T : "OCB-AES-128-16B",
457 M : "000102030405060708090A0B0C0D0E0F",
458 C : "52E48F5D19FE2D9869F0C4A4B3D2BE57",
459 T : "F7EE49AE7AA5B5E6645DB6B3966136F9",
460
461 T : "OCB-AES-128-24B",
462 M : "000102030405060708090A0B0C0D0E0F1011121314151617",
463 C : "F75D6BC8B4DC8D66B836A2B08B32A636CC579E145D323BEB",
464 T : "A1A50F822819D6E0A216784AC24AC84C",
465
466 T : "OCB-AES-128-32B",
467 M : "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F",
468 C : "F75D6BC8B4DC8D66B836A2B08B32A636CEC3C555037571709DA25E1BB0421A27",
469 T : "09CA6C73F0B5C6C5FD587122D75F2AA3",
470
471 T : "OCB-AES-128-40B",
472 M : "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
473 C : "F75D6BC8B4DC8D66B836A2B08B32A6369F1CD3C5228D79FD6C267F5F6AA7B231C7DFB9D59951AE9C",
474 T : "9DB0CDF880F73E3E10D4EB3217766688",
475 }
476 }
477
478 #[test]
479 fn encrypt_and_decrypt_are_inverse() {
480 let mut server_state =
481 ServerCryptState::new_from(Default::default(), Default::default(), Default::default());
482 let mut client_state =
483 ClientCryptState::new_from(Default::default(), Default::default(), Default::default());
484
485 let packet = VoicePacket::Audio {
486 _dst: std::marker::PhantomData,
487 target: 13,
488 session_id: 42,
489 seq_num: 123_567,
490 payload: VoicePacketPayload::Opus(BytesMut::from("test").freeze(), true),
491 position_info: None,
492 };
493
494 let mut buf = BytesMut::new();
495 server_state.encrypt(packet.clone(), &mut buf);
496 let result = client_state
497 .decrypt(&mut buf)
498 .expect("Failed to decrypt")
499 .expect("Failed to decode");
500
501 assert_eq!(packet, result);
502 }
503}