1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-05-05 12:17:45 +00:00

Move encryption stuffs into their own module

This commit is contained in:
Joshua Goins 2025-03-08 16:10:00 -05:00
parent cdc250fca1
commit 51e0f0680e
4 changed files with 90 additions and 68 deletions

View file

@ -1,4 +1,4 @@
use kawari::packet::{parse_packet, State}; use kawari::packet::{State, parse_packet};
use tokio::io::AsyncReadExt; use tokio::io::AsyncReadExt;
use tokio::net::TcpListener; use tokio::net::TcpListener;

54
src/encryption.rs Normal file
View file

@ -0,0 +1,54 @@
use std::io::Cursor;
use binrw::{BinRead, BinResult};
use physis::blowfish::Blowfish;
const GAME_VERSION: u16 = 7000;
pub fn generate_encryption_key(key: &[u8], phrase: &str) -> [u8; 16] {
let mut base_key = vec![0x78, 0x56, 0x34, 0x12];
base_key.extend_from_slice(&key);
base_key.extend_from_slice(&GAME_VERSION.to_le_bytes());
base_key.extend_from_slice(&[0; 2]); // padding (possibly for game version?)
base_key.extend_from_slice(&phrase.as_bytes());
md5::compute(&base_key).0
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_encryption_key() {
let key = generate_encryption_key([0x00, 0x00, 0x00, 0x00], "foobar");
assert_eq!(
key,
[
169, 78, 235, 31, 57, 151, 26, 74, 250, 196, 1, 120, 206, 173, 202, 48
]
);
}
}
#[binrw::parser(reader, endian)]
pub(crate) fn decrypt<T>(size: u32, encryption_key: Option<&[u8]>) -> BinResult<T>
where
for<'a> T: BinRead<Args<'a> = ()> + 'a,
{
let Some(encryption_key) = encryption_key else {
panic!("This segment type is encrypted and no key was provided!");
};
let size = size - 16; // 16 = header size
let mut data = Vec::new();
data.resize(size as usize, 0x0);
reader.read_exact(&mut data)?;
let blowfish = Blowfish::new(encryption_key);
let decrypted_data = blowfish.decrypt(&data).unwrap();
let mut cursor = Cursor::new(&decrypted_data);
T::read_options(&mut cursor, endian, ())
}

View file

@ -3,6 +3,7 @@ use rand::Rng;
use rand::distributions::Alphanumeric; use rand::distributions::Alphanumeric;
pub mod config; pub mod config;
pub mod encryption;
pub mod packet; pub mod packet;
pub mod patchlist; pub mod patchlist;

View file

@ -1,8 +1,17 @@
use std::{fs::write, io::Cursor, time::{SystemTime, UNIX_EPOCH}}; use std::{
fs::write,
io::Cursor,
time::{SystemTime, UNIX_EPOCH},
};
use binrw::{binrw, helpers::until_eof, BinRead, BinResult, BinWrite}; use binrw::{BinRead, BinResult, BinWrite, binrw, helpers::until_eof};
use physis::blowfish::Blowfish; use physis::blowfish::Blowfish;
use tokio::{io::{AsyncWriteExt, WriteHalf}, net::TcpStream}; use tokio::{
io::{AsyncWriteExt, WriteHalf},
net::TcpStream,
};
use crate::encryption::{decrypt, generate_encryption_key};
pub(crate) fn read_bool_from<T: std::convert::From<u8> + std::cmp::PartialEq>(x: T) -> bool { pub(crate) fn read_bool_from<T: std::convert::From<u8> + std::cmp::PartialEq>(x: T) -> bool {
x == T::from(1u8) x == T::from(1u8)
@ -30,29 +39,7 @@ enum ConnectionType {
#[binrw] #[binrw]
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct IPCSegment { struct IPCSegment {
unk: u32 unk: u32,
}
#[binrw::parser(reader, endian)]
pub(crate) fn decrypt<T>(size: u32, encryption_key: Option<&[u8]>) -> BinResult<T>
where
for<'a> T: BinRead<Args<'a> = ()> + 'a
{
let Some(encryption_key) = encryption_key else {
panic!("This segment type is encrypted and no key was provided!");
};
let size = size - 16; // 16 = header size
let mut data = Vec::new();
data.resize(size as usize, 0x0);
reader.read_exact(&mut data)?;
let blowfish = Blowfish::new(encryption_key);
let decrypted_data = blowfish.decrypt(&data).unwrap();
let mut cursor = Cursor::new(&decrypted_data);
T::read_options(&mut cursor, endian, ())
} }
#[binrw] #[binrw]
@ -82,7 +69,7 @@ enum SegmentType {
#[brw(magic = 0x0Au32)] #[brw(magic = 0x0Au32)]
InitializationEncryptionResponse { InitializationEncryptionResponse {
#[br(count = 0x280)] #[br(count = 0x280)]
data: Vec<u8> data: Vec<u8>,
}, },
} }
@ -118,7 +105,8 @@ struct PacketSegment {
impl PacketSegment { impl PacketSegment {
fn calc_size(&self) -> u32 { fn calc_size(&self) -> u32 {
let header = std::mem::size_of::<u32>() * 4; let header = std::mem::size_of::<u32>() * 4;
return header as u32 + match &self.segment_type { return header as u32
+ match &self.segment_type {
SegmentType::InitializeEncryption { .. } => 616, SegmentType::InitializeEncryption { .. } => 616,
SegmentType::InitializationEncryptionResponse { .. } => 640, SegmentType::InitializationEncryptionResponse { .. } => 640,
SegmentType::IPC { .. } => todo!(), SegmentType::IPC { .. } => todo!(),
@ -187,13 +175,16 @@ async fn send_packet(socket: &mut WriteHalf<TcpStream>, segments: &[PacketSegmen
// temporary // temporary
pub struct State { pub struct State {
pub client_key: Option<[u8; 16]> pub client_key: Option<[u8; 16]>,
} }
pub async fn parse_packet(socket: &mut WriteHalf<TcpStream>, data: &[u8], state: &mut State) { pub async fn parse_packet(socket: &mut WriteHalf<TcpStream>, data: &[u8], state: &mut State) {
let mut cursor = Cursor::new(data); let mut cursor = Cursor::new(data);
match Packet::read_le_args(&mut cursor, (state.client_key.as_ref().map(|s: &[u8; 16]| s.as_slice()),)) { match Packet::read_le_args(
&mut cursor,
(state.client_key.as_ref().map(|s: &[u8; 16]| s.as_slice()),),
) {
Ok(packet) => { Ok(packet) => {
println!("{:#?}", packet); println!("{:#?}", packet);
@ -217,46 +208,22 @@ pub async fn parse_packet(socket: &mut WriteHalf<TcpStream>, data: &[u8], state:
let response_packet = PacketSegment { let response_packet = PacketSegment {
source_actor: 0, source_actor: 0,
target_actor: 0, target_actor: 0,
segment_type: SegmentType::InitializationEncryptionResponse { segment_type: SegmentType::InitializationEncryptionResponse { data },
data
},
}; };
send_packet(socket, &[response_packet]).await; send_packet(socket, &[response_packet]).await;
}, }
SegmentType::InitializationEncryptionResponse { .. } => panic!("The server is recieving a response packet!"), SegmentType::InitializationEncryptionResponse { .. } => {
panic!("The server is recieving a response packet!")
}
SegmentType::IPC { .. } => { SegmentType::IPC { .. } => {
// decrypt // decrypt
},
} }
} }
}
}, }
Err(err) => { Err(err) => {
println!("{err}"); println!("{err}");
dump("Failed to parse packet!", data); dump("Failed to parse packet!", data);
}, }
}
}
const GAME_VERSION: u16 = 7000;
pub fn generate_encryption_key(key: &[u8], phrase: &str) -> [u8; 16] {
let mut base_key = vec![0x78, 0x56, 0x34, 0x12];
base_key.extend_from_slice(&key);
base_key.extend_from_slice(&GAME_VERSION.to_le_bytes());
base_key.extend_from_slice(&[0; 2]); // padding (possibly for game version?)
base_key.extend_from_slice(&phrase.as_bytes());
md5::compute(&base_key).0
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_encryption_key() {
let key = generate_encryption_key([0x00, 0x00, 0x00, 0x00], "foobar");
assert_eq!(key, [169, 78, 235, 31, 57, 151, 26, 74, 250, 196, 1, 120, 206, 173, 202, 48]);
} }
} }