From 300c3c2c13eb2dacdc15f92d2f0c220beb5f9be4 Mon Sep 17 00:00:00 2001 From: Kyler <59854022+KylerOlsen@users.noreply.github.com> Date: Fri, 31 May 2024 16:20:58 -0600 Subject: [PATCH] Added encryption --- Cargo.toml | 6 ++ src/encrypt.rs | 46 ++++++++++ src/handshake.rs | 8 +- src/lib.rs | 2 + src/login.rs | 16 ++-- src/mc_types.rs | 224 ++++++++++++++++++++++++++++++++++++++++++----- src/play.rs | 39 +++++++++ src/status.rs | 15 ++-- 8 files changed, 314 insertions(+), 42 deletions(-) create mode 100644 src/encrypt.rs create mode 100644 src/play.rs diff --git a/Cargo.toml b/Cargo.toml index 535214f..ec5e14a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,9 @@ tokio = { version = "1", features = ["full"] } serde = { version = "1", features = ["derive"] } serde_json = "1" async-trait = "0.1.75" +rand = "0.8.5" +# aes = "0.8.4" +aes = "0.7" +# rsa = "0.9.6" +rsa = "0.6" +pkcs8 = "0.8" diff --git a/src/encrypt.rs b/src/encrypt.rs new file mode 100644 index 0000000..19e778e --- /dev/null +++ b/src/encrypt.rs @@ -0,0 +1,46 @@ +// Yeahbut May 2024 + +use rsa::PublicKey; +use rsa::{RsaPrivateKey, RsaPublicKey, PaddingScheme, errors::Result}; +use rand::rngs::OsRng; +use aes::Aes128; +use aes::cipher::{ + BlockEncrypt, BlockDecrypt, NewBlockCipher, generic_array::GenericArray}; + +pub fn generate_rsa_keys() -> Result { + let mut rng = OsRng; + let bits = 2048; + let private_key = RsaPrivateKey::new(&mut rng, bits)?; + Ok(private_key) +} + +pub fn encrypt_rsa( + public_key: &RsaPublicKey, + data: &[u8; 16], +) -> Result> { + let padding = PaddingScheme::new_pkcs1v15_encrypt(); + let mut rng = OsRng; + public_key.encrypt(&mut rng, padding, data) +} + +pub fn decrypt_rsa( + private_key: &RsaPrivateKey, + data: &[u8], +) -> Result> { + let padding = PaddingScheme::new_pkcs1v15_encrypt(); + private_key.decrypt(padding, data) +} + +pub fn encrypt_aes(key: &[u8; 16], data: &[u8; 16]) -> Vec { + let cipher = Aes128::new(GenericArray::from_slice(key)); + let mut block = GenericArray::clone_from_slice(data); + cipher.encrypt_block(&mut block); + block.to_vec() +} + +pub fn decrypt_aes(key: &[u8; 16], data: &[u8; 16]) -> Vec { + let cipher = Aes128::new(GenericArray::from_slice(key)); + let mut block = GenericArray::clone_from_slice(data); + cipher.decrypt_block(&mut block); + block.to_vec() +} diff --git a/src/handshake.rs b/src/handshake.rs index 8537dfb..cbdff5d 100644 --- a/src/handshake.rs +++ b/src/handshake.rs @@ -2,8 +2,6 @@ pub mod serverbound { - use tokio::net::tcp::OwnedReadHalf; - use crate::mc_types::{self, Result, Packet, PacketError}; pub enum HandshakeEnum { @@ -11,8 +9,10 @@ pub mod serverbound { } impl HandshakeEnum { - pub async fn read(stream: &mut OwnedReadHalf) -> Result { - let mut data = mc_types::read_data(stream).await?; + pub async fn read( + conn: &mut mc_types::ProtocolConnection<'_>, + ) -> Result { + let mut data = conn.read_data().await?; let packet_id = mc_types::get_var_int(&mut data)?; if packet_id == Handshake::packet_id() { return Ok(Self::Handshake(Handshake::get(&mut data)?)) diff --git a/src/lib.rs b/src/lib.rs index b64644a..c60aa4f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,3 +4,5 @@ pub mod mc_types; pub mod handshake; pub mod status; pub mod login; +pub mod encrypt; +pub mod play; diff --git a/src/login.rs b/src/login.rs index c0074c9..5784eb4 100644 --- a/src/login.rs +++ b/src/login.rs @@ -2,8 +2,6 @@ pub mod clientbound { - use tokio::net::tcp::OwnedReadHalf; - use crate::mc_types::{self, Result, Packet, PacketArray, PacketError}; pub enum Login { @@ -15,8 +13,10 @@ pub mod clientbound { } impl Login { - pub async fn read(stream: &mut OwnedReadHalf) -> Result { - let mut data = mc_types::read_data(stream).await?; + pub async fn read( + conn: &mut mc_types::ProtocolConnection<'_>, + ) -> Result { + let mut data = conn.read_data().await?; let packet_id = mc_types::get_var_int(&mut data)?; if packet_id == Disconnect::packet_id() { return Ok(Self::Disconnect(Disconnect::get(&mut data)?)) @@ -232,8 +232,6 @@ pub mod clientbound { pub mod serverbound { - use tokio::net::tcp::OwnedReadHalf; - use crate::mc_types::{self, Result, Packet, PacketError}; pub enum Login { @@ -243,8 +241,10 @@ pub mod serverbound { } impl Login { - pub async fn read(stream: &mut OwnedReadHalf) -> Result { - let mut data = mc_types::read_data(stream).await?; + pub async fn read( + conn: &mut mc_types::ProtocolConnection<'_>, + ) -> Result { + let mut data = conn.read_data().await?; let packet_id = mc_types::get_var_int(&mut data)?; if packet_id == LoginStart::packet_id() { return Ok(Self::LoginStart(LoginStart::get(&mut data)?)) diff --git a/src/mc_types.rs b/src/mc_types.rs index f9d6b2a..b2e11e5 100644 --- a/src/mc_types.rs +++ b/src/mc_types.rs @@ -7,6 +7,12 @@ use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use serde::{Serialize, Deserialize}; use async_trait::async_trait; +use rsa::{RsaPrivateKey, RsaPublicKey}; +use rsa::pkcs8::{EncodePublicKey, DecodePublicKey}; +use rand::Rng; + +use crate::login; +use crate::encrypt; pub type Result = std::result::Result>; @@ -21,6 +27,7 @@ pub enum PacketError { ValueTooLarge, RanOutOfBytes, InvalidPacketId, + EncryptionError, } impl fmt::Display for PacketError { @@ -32,6 +39,8 @@ impl fmt::Display for PacketError { write!(f, "Ran out of bytes while reading VarInt"), PacketError::InvalidPacketId => write!(f, "Invalid packet id"), + PacketError::EncryptionError => + write!(f, "Encryption Error"), } } } @@ -43,14 +52,185 @@ pub struct Chat { pub text: String, } +pub struct ProtocolConnection<'a> { + pub stream_read: &'a mut OwnedReadHalf, + pub stream_write: &'a mut OwnedWriteHalf, + rsa_private_key: Option, + rsa_public_key: Option, + aes_encryption_key: Option<[u8; 16]>, + verify_token: Option<[u8; 16]>, +} + +impl<'a> ProtocolConnection<'a> { + pub async fn read_data(&mut self) -> Result> { + match self.aes_encryption_key { + Some(aes_key) => { + let mut buffer: Vec = vec![0; 16]; + self.stream_read.read_exact(&mut buffer).await?; + buffer = encrypt::decrypt_aes( + &aes_key, buffer[0..16].try_into().unwrap()); + let raw_length = read_var_int_vec(&mut buffer)?; + let length = + if (raw_length - buffer.len() as i32) % 16 == 0 { + (raw_length - buffer.len() as i32) / 16 + } else { + ((raw_length - buffer.len() as i32) / 16) + 1 + }; + + for _ in 0..length { + let mut block: Vec = vec![0; 16]; + self.stream_read.read_exact(&mut block).await?; + buffer.append(&mut block); + } + + Ok(buffer) + }, + None => { + let length = read_var_int_stream( + self.stream_read).await? as usize; + + let mut buffer: Vec = vec![0; length]; + self.stream_read.read_exact(&mut buffer).await?; + + Ok(buffer) + } + } + } + + pub async fn write_data( + &mut self, + data: &mut Vec, + ) -> Result<()> { + let mut out_data = convert_var_int(data.len() as i32); + out_data.append(data); + match self.aes_encryption_key { + Some(aes_key) => { + let length = + if (data.len() as i32) % 16 == 0 { + (data.len() as i32) / 16 + } else { + ((data.len() as i32) / 16) + 1 + }; + + for _ in 0..length { + let mut block: Vec = out_data[0..16].to_vec(); + block = encrypt::encrypt_aes( + &aes_key, block[0..16].try_into().unwrap()); + self.stream_write.write_all(&block).await?; + } + + + Ok(()) + }, + None => { + self.stream_write.write_all(&out_data).await?; + + Ok(()) + } + } + } + + pub fn create_encryption_request( + &mut self, + private_key: RsaPrivateKey, + ) -> Result { + match self.rsa_private_key { + Some(_) => {}, + None => { + let public_key = RsaPublicKey::from(&private_key); + let mut rng = rand::thread_rng(); + self.rsa_private_key = Some(private_key); + self.rsa_public_key = Some(public_key); + self.verify_token = Some(rng.gen()); + } + }; + match &self.rsa_public_key { + Some (key) => { + match &self.verify_token { + Some (token) => + Ok(login::clientbound::EncryptionRequest { + server_id: "".to_string(), + public_key: key + .to_public_key_der()? + .as_ref() + .to_vec(), + verify_token: token[0..16].to_vec(), + }), + None => Err(Box::new(PacketError::EncryptionError)) + } + }, + None => Err(Box::new(PacketError::EncryptionError)) + } + } + + pub fn handle_encryption_request( + &mut self, + request: login::clientbound::EncryptionRequest, + ) -> Result { + self.rsa_public_key = Some( + RsaPublicKey::from_public_key_der(&request.public_key)?); + let mut rng = rand::thread_rng(); + self.aes_encryption_key = Some(rng.gen()); + match self.aes_encryption_key { + Some(key) => { + match &self.rsa_public_key { + Some(public_key) => { + Ok(login::serverbound::EncryptionResponse { + shared_secret: encrypt::encrypt_rsa( + public_key, &key)?, + verify_token: encrypt::encrypt_rsa( + public_key, + request.verify_token[0..16] + .try_into() + .unwrap(), + )?, + }) + }, + None => Err(Box::new(PacketError::EncryptionError)) + } + }, + None => Err(Box::new(PacketError::EncryptionError)) + } + } + + pub fn handle_encryption_response( + &mut self, + response: login::serverbound::EncryptionResponse, + ) -> Result<()> { + match &self.verify_token { + Some (token) => { + match &self.rsa_private_key { + Some (private_key) => { + if &encrypt::decrypt_rsa( + &private_key, + response.verify_token.as_slice() + )? == token { + self.aes_encryption_key = + Some(encrypt::decrypt_rsa( + &private_key, + response.shared_secret.as_slice() + )?[0..16].try_into().unwrap()); + Ok(()) + } else { + Err(Box::new(PacketError::EncryptionError)) + } + } + None => Err(Box::new(PacketError::EncryptionError)) + } + } + None => Err(Box::new(PacketError::EncryptionError)) + } + } +} + #[async_trait] pub trait Packet: Sized { fn packet_id() -> i32; fn get(data: &mut Vec) -> Result; fn convert(&self) -> Vec; - async fn read(stream: &mut OwnedReadHalf) -> Result { - let mut data = read_data(stream).await?; + async fn read(conn: &mut ProtocolConnection<'_>) -> Result { + let mut data = conn.read_data().await?; let packet_id = get_var_int(&mut data)?; if packet_id == Self::packet_id() { return Ok(Self::get(&mut data)?) @@ -59,30 +239,11 @@ pub trait Packet: Sized { } } - async fn write(&self, stream: &mut OwnedWriteHalf) -> Result<()> { - write_data(stream, &mut self.convert()).await + async fn write(&self, conn: &mut ProtocolConnection<'_>) -> Result<()> { + conn.write_data(&mut self.convert()).await } } -pub async fn read_data(stream: &mut OwnedReadHalf) -> Result> { - let length = read_var_int_stream(stream).await? as usize; - - let mut buffer: Vec = vec![0; length]; - stream.read_exact(&mut buffer).await?; - - Ok(buffer) -} -pub async fn write_data( - stream: &mut OwnedWriteHalf, - data: &mut Vec, -) -> Result<()> { - let mut out_data = convert_var_int(data.len() as i32); - out_data.append(data); - - stream.write_all(&out_data).await?; - - Ok(()) -} async fn read_var_int_stream(stream: &mut OwnedReadHalf) -> Result { let mut data: Vec = vec![]; @@ -100,6 +261,23 @@ async fn read_var_int_stream(stream: &mut OwnedReadHalf) -> Result { Ok(varint) } +fn read_var_int_vec(stream: &mut Vec) -> Result { + let mut data: Vec = vec![]; + + loop { + let current_byte = stream.remove(0); + + data.append(&mut vec![current_byte]); + + if (current_byte & CONTINUE_BIT) == 0 { + break; + } + } + + let varint = get_var_int(&mut data)?; + + Ok(varint) +} pub trait PacketArray: Sized { fn get(data: &mut Vec) -> Result; diff --git a/src/play.rs b/src/play.rs new file mode 100644 index 0000000..52ad9a3 --- /dev/null +++ b/src/play.rs @@ -0,0 +1,39 @@ + +use crate::mc_types::{self, Packet, Result}; + + +pub enum Play { + PlayPacket(PlayPacket), +} + +impl Play { + pub async fn read( + conn: &mut mc_types::ProtocolConnection<'_>, + ) -> Result { + let mut data = conn.read_data().await?; + Ok(Self::PlayPacket(PlayPacket::get(&mut data)?)) + } +} + +pub struct PlayPacket { + pub data: Vec +} + +impl Packet for PlayPacket { + + fn packet_id() -> i32 {0} + + fn get(data: &mut Vec) -> Result { + Ok(Self { + data: data.clone() + }) + } + + fn convert(&self) -> Vec { + let mut data: Vec = vec![]; + data.append(&mut self.data.clone()); + + data + } + +} diff --git a/src/status.rs b/src/status.rs index efec893..e20f18e 100644 --- a/src/status.rs +++ b/src/status.rs @@ -2,7 +2,6 @@ pub mod clientbound { - use tokio::net::tcp::OwnedReadHalf; use serde::{Serialize, Deserialize}; use crate::mc_types::{self, Result, Packet, PacketError}; @@ -46,8 +45,10 @@ pub mod clientbound { } impl StatusPackets { - pub async fn read(stream: &mut OwnedReadHalf) -> Result { - let mut data = mc_types::read_data(stream).await?; + pub async fn read( + conn: &mut mc_types::ProtocolConnection<'_>, + ) -> Result { + let mut data = conn.read_data().await?; let packet_id = mc_types::get_var_int(&mut data)?; if packet_id == Status::packet_id() { return Ok(Self::Status(Status::get(&mut data)?)) @@ -125,8 +126,6 @@ pub mod clientbound { pub mod serverbound { - use tokio::net::tcp::OwnedReadHalf; - use crate::mc_types::{self, Result, Packet, PacketError}; pub enum StatusPackets { @@ -135,8 +134,10 @@ pub mod serverbound { } impl StatusPackets { - pub async fn read(stream: &mut OwnedReadHalf) -> Result { - let mut data = mc_types::read_data(stream).await?; + pub async fn read( + conn: &mut mc_types::ProtocolConnection<'_>, + ) -> Result { + let mut data = conn.read_data().await?; let packet_id = mc_types::get_var_int(&mut data)?; if packet_id == Status::packet_id() { return Ok(Self::Status(Status::get(&mut data)?))