2025-03-11 18:39:30 -04:00
|
|
|
use std::io::Cursor;
|
2025-03-08 16:10:00 -05:00
|
|
|
|
2025-03-16 17:43:29 -04:00
|
|
|
use binrw::BinResult;
|
2025-03-08 21:13:00 -05:00
|
|
|
|
2025-03-23 08:33:07 -04:00
|
|
|
use crate::{GAME_VERSION, blowfish::Blowfish};
|
2025-03-08 16:10:00 -05:00
|
|
|
|
2025-03-17 17:12:40 -04:00
|
|
|
use super::ReadWriteIpcSegment;
|
2025-03-16 17:43:29 -04:00
|
|
|
|
2025-03-08 16:10:00 -05:00
|
|
|
pub fn generate_encryption_key(key: &[u8], phrase: &str) -> [u8; 16] {
|
|
|
|
let mut base_key = vec![0x78, 0x56, 0x34, 0x12];
|
2025-03-08 21:54:03 -05:00
|
|
|
base_key.extend_from_slice(key);
|
2025-03-08 16:10:00 -05:00
|
|
|
base_key.extend_from_slice(&GAME_VERSION.to_le_bytes());
|
|
|
|
base_key.extend_from_slice(&[0; 2]); // padding (possibly for game version?)
|
2025-03-08 21:54:03 -05:00
|
|
|
base_key.extend_from_slice(phrase.as_bytes());
|
2025-03-08 16:10:00 -05:00
|
|
|
|
|
|
|
md5::compute(&base_key).0
|
|
|
|
}
|
|
|
|
|
|
|
|
#[binrw::parser(reader, endian)]
|
2025-03-17 17:12:40 -04:00
|
|
|
pub(crate) fn decrypt<T: ReadWriteIpcSegment>(
|
2025-03-16 17:43:29 -04:00
|
|
|
size: u32,
|
|
|
|
encryption_key: Option<&[u8]>,
|
|
|
|
) -> BinResult<T> {
|
2025-03-10 21:31:21 -04:00
|
|
|
if let Some(encryption_key) = encryption_key {
|
|
|
|
let size = size - (std::mem::size_of::<u32>() * 4) as u32; // 16 = header size
|
2025-03-08 16:10:00 -05:00
|
|
|
|
2025-03-10 21:31:21 -04:00
|
|
|
let mut data = vec![0; size as usize];
|
|
|
|
reader.read_exact(&mut data)?;
|
2025-03-08 16:10:00 -05:00
|
|
|
|
2025-03-11 18:39:30 -04:00
|
|
|
let blowfish = Blowfish::new(encryption_key);
|
|
|
|
blowfish.decrypt(&mut data);
|
2025-03-08 16:10:00 -05:00
|
|
|
|
2025-03-11 18:39:30 -04:00
|
|
|
let mut cursor = Cursor::new(&data);
|
|
|
|
T::read_options(&mut cursor, endian, ())
|
2025-03-10 21:31:21 -04:00
|
|
|
} else {
|
|
|
|
tracing::info!("NOTE: Not decrypting this IPC packet since no key was provided!");
|
2025-03-09 00:06:54 -05:00
|
|
|
|
2025-03-10 21:31:21 -04:00
|
|
|
T::read_options(reader, endian, ())
|
2025-03-08 21:13:00 -05:00
|
|
|
}
|
2025-03-08 16:10:00 -05:00
|
|
|
}
|
2025-03-08 21:53:10 -05:00
|
|
|
|
|
|
|
#[binrw::writer(writer, endian)]
|
2025-03-17 17:12:40 -04:00
|
|
|
pub(crate) fn encrypt<T: ReadWriteIpcSegment>(
|
2025-03-16 17:43:29 -04:00
|
|
|
value: &T,
|
|
|
|
size: u32,
|
|
|
|
encryption_key: Option<&[u8]>,
|
|
|
|
) -> BinResult<()> {
|
2025-03-10 21:31:21 -04:00
|
|
|
if let Some(encryption_key) = encryption_key {
|
|
|
|
let size = size - (std::mem::size_of::<u32>() * 4) as u32; // 16 = header size
|
|
|
|
|
|
|
|
let mut cursor = Cursor::new(Vec::new());
|
|
|
|
value.write_options(&mut cursor, endian, ())?;
|
|
|
|
|
|
|
|
let mut buffer = cursor.into_inner();
|
|
|
|
buffer.resize(size as usize, 0);
|
|
|
|
|
2025-03-11 18:39:30 -04:00
|
|
|
let blowfish = Blowfish::new(encryption_key);
|
|
|
|
blowfish.encrypt(&mut buffer);
|
|
|
|
|
|
|
|
writer.write_all(&buffer)?;
|
|
|
|
|
|
|
|
Ok(())
|
2025-03-10 21:31:21 -04:00
|
|
|
} else {
|
|
|
|
tracing::info!("NOTE: Not encrypting this IPC packet since no key was provided!");
|
|
|
|
|
|
|
|
value.write_options(writer, endian, ())
|
2025-03-08 21:53:10 -05:00
|
|
|
}
|
|
|
|
}
|
2025-03-08 21:54:03 -05:00
|
|
|
|
|
|
|
#[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
|
|
|
|
]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|