Pumpkin/pumpkin-protocol/src/packet_decoder.rs
Snowiiii cbf9e63329 Remove ByteBuffer struct
Replaced trough trait's which implement bytes::Buf and bytes::BufMut.
Closes https://github.com/Snowiiii/Pumpkin/issues/396
2024-12-13 15:42:04 +01:00

502 lines
17 KiB
Rust

use aes::cipher::{generic_array::GenericArray, BlockDecryptMut, BlockSizeUser, KeyIvInit};
use bytes::{Buf, Bytes, BytesMut};
use libdeflater::{DecompressionError, Decompressor};
use thiserror::Error;
use crate::{RawPacket, VarInt, VarIntDecodeError, MAX_PACKET_SIZE};
type Cipher = cfb8::Decryptor<aes::Aes128>;
// Decoder: Client -> Server
// Supports ZLib decoding/decompression
// Supports Aes128 Encryption
pub struct PacketDecoder {
buf: BytesMut,
decompress_buf: BytesMut,
compression: bool,
cipher: Option<Cipher>,
decompressor: Decompressor,
}
// Manual implementation of Default trait for PacketDecoder
// Since decompressor does not implement Default
impl Default for PacketDecoder {
fn default() -> Self {
Self {
buf: BytesMut::new(),
decompress_buf: BytesMut::new(),
compression: false,
cipher: None,
decompressor: Decompressor::new(),
}
}
}
impl PacketDecoder {
pub fn decode(&mut self) -> Result<Option<RawPacket>, PacketDecodeError> {
let mut r = &self.buf[..];
let packet_len = match VarInt::decode(&mut r) {
Ok(len) => len,
Err(VarIntDecodeError::Incomplete) => return Ok(None),
Err(VarIntDecodeError::TooLarge) => Err(PacketDecodeError::MalformedLength)?,
};
let packet_len = packet_len.0;
if !(0..=MAX_PACKET_SIZE).contains(&packet_len) {
Err(PacketDecodeError::OutOfBounds)?
}
if r.len() < packet_len as usize {
// Not enough data arrived yet.
return Ok(None);
}
let packet_len_len = VarInt(packet_len).written_size();
let mut data;
if self.compression {
r = &r[..packet_len as usize];
let data_len = VarInt::decode(&mut r)
.map_err(|_| PacketDecodeError::TooLong)?
.0;
if !(0..=MAX_PACKET_SIZE).contains(&data_len) {
Err(PacketDecodeError::OutOfBounds)?
}
// Is this packet compressed?
if data_len > 0 {
debug_assert!(self.decompress_buf.is_empty());
// Estimate the maximum decompressed size.
self.decompress_buf.resize(data_len as usize, 0);
// Perform decompression using libdeflater
let decompressed_size = self
.decompressor
.zlib_decompress(r, &mut self.decompress_buf)
.map_err(PacketDecodeError::from)?;
if decompressed_size != data_len as usize {
return Err(PacketDecodeError::FailedDecompression(format!(
"Expected {} bytes, got {} bytes",
data_len, decompressed_size
)));
}
self.decompress_buf.truncate(decompressed_size);
let total_packet_len = VarInt(packet_len).written_size() + packet_len as usize;
self.buf.advance(total_packet_len);
data = self.decompress_buf.split();
} else {
debug_assert_eq!(data_len, 0);
let remaining_len = r.len();
self.buf.advance(packet_len_len + 1);
data = self.buf.split_to(remaining_len);
}
} else {
// no compression
self.buf.advance(packet_len_len);
data = self.buf.split_to(packet_len as usize);
}
r = &data[..];
let packet_id = VarInt::decode(&mut r).map_err(|_| PacketDecodeError::DecodeID)?;
data.advance(data.len() - r.len());
Ok(Some(RawPacket {
id: packet_id,
bytebuf: Bytes::from(data),
}))
}
pub fn set_encryption(&mut self, key: Option<&[u8; 16]>) {
if let Some(key) = key {
assert!(self.cipher.is_none(), "encryption is already enabled");
let mut cipher = Cipher::new_from_slices(key, key).expect("invalid key");
// Don't forget to decrypt the data we already have.
Self::decrypt_bytes(&mut cipher, &mut self.buf);
self.cipher = Some(cipher);
} else {
assert!(self.cipher.is_some(), "encryption is already disabled");
self.cipher = None;
}
}
/// Sets ZLib Decompression
pub fn set_compression(&mut self, compression: bool) {
self.compression = compression;
}
fn decrypt_bytes(cipher: &mut Cipher, bytes: &mut [u8]) {
for chunk in bytes.chunks_mut(Cipher::block_size()) {
let gen_arr = GenericArray::from_mut_slice(chunk);
cipher.decrypt_block_mut(gen_arr);
}
}
pub fn queue_bytes(&mut self, mut bytes: BytesMut) {
if let Some(cipher) = &mut self.cipher {
Self::decrypt_bytes(cipher, &mut bytes);
}
self.buf.unsplit(bytes);
}
pub fn queue_slice(&mut self, bytes: &[u8]) {
let len = self.buf.len();
self.buf.extend_from_slice(bytes);
if let Some(cipher) = &mut self.cipher {
let slice = &mut self.buf[len..];
Self::decrypt_bytes(cipher, slice);
}
}
pub fn take_capacity(&mut self) -> BytesMut {
self.buf.split_off(self.buf.len())
}
pub fn clear(&mut self) {
self.buf.clear()
}
pub fn reserve(&mut self, additional: usize) {
self.buf.reserve(additional);
}
}
#[derive(Error, Debug)]
pub enum PacketDecodeError {
#[error("failed to decode packet ID")]
DecodeID,
#[error("packet exceeds maximum length")]
TooLong,
#[error("packet length is out of bounds")]
OutOfBounds,
#[error("malformed packet length VarInt")]
MalformedLength,
#[error("failed to decompress packet: {0}")]
FailedDecompression(String), // Updated to include error details
}
impl From<DecompressionError> for PacketDecodeError {
fn from(error: DecompressionError) -> Self {
PacketDecodeError::FailedDecompression(error.to_string())
}
}
#[cfg(test)]
mod tests {
use crate::bytebuf::ByteBufMut;
use super::*;
use aes::Aes128;
use bytes::BufMut;
use cfb8::cipher::AsyncStreamCipher;
use cfb8::Encryptor as Cfb8Encryptor;
use libdeflater::{CompressionLvl, Compressor};
/// Helper function to compress data using libdeflater's Zlib compressor
fn compress_zlib(data: &[u8]) -> Vec<u8> {
let mut compressor = Compressor::new(CompressionLvl::default()); // Using compression level 6
let mut compressed = vec![0u8; compressor.zlib_compress_bound(data.len())];
let compressed_size = compressor
.zlib_compress(data, &mut compressed)
.expect("Compression failed");
compressed.truncate(compressed_size);
compressed
}
/// Helper function to encrypt data using AES-128 CFB-8 mode
fn encrypt_aes128(data: &mut [u8], key: &[u8; 16], iv: &[u8; 16]) {
let encryptor = Cfb8Encryptor::<Aes128>::new_from_slices(key, iv).expect("Invalid key/iv");
encryptor.encrypt(data);
}
/// Helper function to build a packet with optional compression and encryption
fn build_packet(
packet_id: i32,
payload: &[u8],
compress: bool,
key: Option<&[u8; 16]>,
iv: Option<&[u8; 16]>,
) -> Vec<u8> {
let mut buffer = BytesMut::new();
if compress {
// Create a buffer that includes packet_id_varint and payload
let mut data_to_compress = BytesMut::new();
let packet_id_varint = VarInt(packet_id);
data_to_compress.put_var_int(&packet_id_varint);
data_to_compress.put_slice(payload);
// Compress the combined data
let compressed_payload = compress_zlib(&data_to_compress);
let data_len = data_to_compress.len() as i32; // 1 + payload.len()
let data_len_varint = VarInt(data_len);
buffer.put_var_int(&data_len_varint);
buffer.put_slice(&compressed_payload);
} else {
// No compression; data_len is payload length
let packet_id_varint = VarInt(packet_id);
buffer.put_var_int(&packet_id_varint);
buffer.put_slice(payload);
}
// Calculate packet length: length of buffer
let packet_len = buffer.len() as i32;
let packet_len_varint = VarInt(packet_len);
let mut packet_length_encoded = Vec::new();
{
packet_len_varint.encode(&mut packet_length_encoded);
}
// Create a new buffer for the entire packet
let mut packet = Vec::new();
packet.extend_from_slice(&packet_length_encoded);
packet.extend_from_slice(&buffer);
// Encrypt if key and iv are provided
if let (Some(k), Some(v)) = (key, iv) {
encrypt_aes128(&mut packet, k, v);
packet
} else {
packet
}
}
/// Test decoding without compression and encryption
#[test]
fn test_decode_without_compression_and_encryption() {
// Sample packet data: packet_id = 1, payload = "Hello"
let packet_id = 1;
let payload = b"Hello";
// Build the packet without compression and encryption
let packet = build_packet(packet_id, payload, false, None, None);
// Initialize the decoder without compression and encryption
let mut decoder = PacketDecoder::default();
decoder.set_compression(false);
// Feed the packet to the decoder
decoder.queue_slice(&packet);
// Attempt to decode
let result = decoder.decode().expect("Decoding failed");
assert!(result.is_some());
let raw_packet = result.unwrap();
assert_eq!(raw_packet.id.0, packet_id);
assert_eq!(raw_packet.bytebuf.as_ref(), payload);
}
/// Test decoding with compression
#[test]
fn test_decode_with_compression() {
// Sample packet data: packet_id = 2, payload = "Hello, compressed world!"
let packet_id = 2;
let payload = b"Hello, compressed world!";
// Build the packet with compression enabled
let packet = build_packet(packet_id, payload, true, None, None);
// Initialize the decoder with compression enabled
let mut decoder = PacketDecoder::default();
decoder.set_compression(true);
// Feed the packet to the decoder
decoder.queue_slice(&packet);
// Attempt to decode
let result = decoder.decode().expect("Decoding failed");
assert!(result.is_some());
let raw_packet = result.unwrap();
assert_eq!(raw_packet.id.0, packet_id);
assert_eq!(raw_packet.bytebuf.as_ref(), payload);
}
/// Test decoding with encryption
#[test]
fn test_decode_with_encryption() {
// Sample packet data: packet_id = 3, payload = "Hello, encrypted world!"
let packet_id = 3;
let payload = b"Hello, encrypted world!";
// Define encryption key and IV
let key = [0x00u8; 16]; // Example key
let iv = [0x00u8; 16]; // Example IV
// Build the packet with encryption enabled (no compression)
let packet = build_packet(packet_id, payload, false, Some(&key), Some(&iv));
// Initialize the decoder with encryption enabled
let mut decoder = PacketDecoder::default();
decoder.set_compression(false);
decoder.set_encryption(Some(&key));
// Feed the encrypted packet to the decoder
decoder.queue_slice(&packet);
// Attempt to decode
let result = decoder.decode().expect("Decoding failed");
assert!(result.is_some());
let raw_packet = result.unwrap();
assert_eq!(raw_packet.id.0, packet_id);
assert_eq!(raw_packet.bytebuf.as_ref(), payload);
}
/// Test decoding with both compression and encryption
#[test]
fn test_decode_with_compression_and_encryption() {
// Sample packet data: packet_id = 4, payload = "Hello, compressed and encrypted world!"
let packet_id = 4;
let payload = b"Hello, compressed and encrypted world!";
// Define encryption key and IV
let key = [0x01u8; 16]; // Example key
let iv = [0x01u8; 16]; // Example IV
// Build the packet with both compression and encryption enabled
let packet = build_packet(packet_id, payload, true, Some(&key), Some(&iv));
// Initialize the decoder with both compression and encryption enabled
let mut decoder = PacketDecoder::default();
decoder.set_compression(true);
decoder.set_encryption(Some(&key));
// Feed the encrypted and compressed packet to the decoder
decoder.queue_slice(&packet);
// Attempt to decode
let result = decoder.decode().expect("Decoding failed");
assert!(result.is_some());
let raw_packet = result.unwrap();
assert_eq!(raw_packet.id.0, packet_id);
assert_eq!(raw_packet.bytebuf.as_ref(), payload);
}
/// Test decoding with invalid compressed data
#[test]
fn test_decode_with_invalid_compressed_data() {
// Sample packet data: packet_id = 5, payload_len = 10, but compressed data is invalid
let data_len = 10; // Expected decompressed size
let invalid_compressed_data = vec![0xFF, 0xFF, 0xFF]; // Invalid Zlib data
// Build the packet with compression enabled but invalid compressed data
let mut buffer = BytesMut::new();
let data_len_varint = VarInt(data_len);
buffer.put_var_int(&data_len_varint);
buffer.put_slice(&invalid_compressed_data);
// Calculate packet length: VarInt(data_len) + invalid compressed data
let packet_len = buffer.len() as i32;
let packet_len_varint = VarInt(packet_len);
// Create a new buffer for the entire packet
let mut packet_buffer = BytesMut::new();
packet_buffer.put_var_int(&packet_len_varint);
packet_buffer.put_slice(&buffer);
let packet_bytes = packet_buffer;
// Initialize the decoder with compression enabled
let mut decoder = PacketDecoder::default();
decoder.set_compression(true);
// Feed the invalid compressed packet to the decoder
decoder.queue_slice(&packet_bytes);
// Attempt to decode and expect a decompression error
let result = decoder.decode();
assert!(matches!(
result,
Err(PacketDecodeError::FailedDecompression(_))
));
}
/// Test decoding with a zero-length packet
#[test]
fn test_decode_with_zero_length_packet() {
// Sample packet data: packet_id = 7, payload = "" (empty)
let packet_id = 7;
let payload = b"";
// Build the packet without compression and encryption
let packet = build_packet(packet_id, payload, false, None, None);
// Initialize the decoder without compression and encryption
let mut decoder = PacketDecoder::default();
decoder.set_compression(false);
// Feed the packet to the decoder
decoder.queue_slice(&packet);
// Attempt to decode
let result = decoder.decode().expect("Decoding failed");
assert!(result.is_some());
let raw_packet = result.unwrap();
assert_eq!(raw_packet.id.0, packet_id);
assert_eq!(raw_packet.bytebuf.as_ref(), payload);
}
/// Test decoding with maximum length packet
#[test]
fn test_decode_with_maximum_length_packet() {
// Sample packet data: packet_id = 8, payload = "A" repeated MAX_PACKET_SIZE times
// Sample packet data: packet_id = 8, payload = "A" repeated (MAX_PACKET_SIZE - 1) times
let packet_id = 8;
let payload = vec![0x41u8; (MAX_PACKET_SIZE - 1) as usize]; // "A" repeated
// Build the packet with compression enabled
let packet = build_packet(packet_id, &payload, true, None, None);
println!(
"Built packet (with compression, maximum length): {:?}",
packet
);
// Initialize the decoder with compression enabled
let mut decoder = PacketDecoder::default();
decoder.set_compression(true);
// Feed the packet to the decoder
decoder.queue_slice(&packet);
// Attempt to decode
let result = decoder.decode().expect("Decoding failed");
assert!(
result.is_some(),
"Decoder returned None when it should have decoded a packet"
);
let raw_packet = result.unwrap();
assert_eq!(
raw_packet.id.0, packet_id,
"Decoded packet_id does not match"
);
assert_eq!(
raw_packet.bytebuf.as_ref(),
&payload[..],
"Decoded payload does not match"
);
}
}