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