allow non-dword-sized data to be passed in to crypt()

this is not actually recommended, as it _technically_ does "mess up"
the sequence (1-3 zero-bytes are being encrypted along with your 1-3
remaining bytes in non-dword-sized data buffers, but those additional
encrypted zero-bytes are not being given back to you at the end).

however, in my opinion, this is quite unlikely to pose a problem for
anyone. for dealing with PSO packets, i'm pretty sure all of those end
up being dword-sized anyway, so no issue there. for encrypting and
decrypting offline quest data, the compressed bin/dat data _could_
technically be non-dword-sized (as i actually encountered today) so you
would otherwise need to pad the input data before calling crypt()
anyway. and in this case you are not going to be using that very same
Crypter instance to do any further encrypting/decrypting ... so it's
actually no problem at all.

so, to me, the convenience of having crypt() just automatically be able
to deal with any arbitrary size of data was worthwhile.

meh.
This commit is contained in:
Gered 2021-05-18 15:05:00 -04:00
parent c59d115aba
commit 7f8a8f75e0
2 changed files with 78 additions and 80 deletions

View file

@ -7,7 +7,6 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
byte-slice-cast = "0.3.5"
byteorder = "1.4.3" byteorder = "1.4.3"
thiserror = "1.0.24" thiserror = "1.0.24"
encoding_rs = "0.8.28" encoding_rs = "0.8.28"

View file

@ -1,17 +1,44 @@
use byte_slice_cast::AsMutSliceOf;
use thiserror::Error;
const PC_STREAM_LENGTH: usize = 57; const PC_STREAM_LENGTH: usize = 57;
const GC_STREAM_LENGTH: usize = 521; const GC_STREAM_LENGTH: usize = 521;
#[derive(Error, Debug, PartialEq)]
pub enum EncryptionError {
#[error("Error casting input data slice")]
InputDataCastingError(#[from] byte_slice_cast::Error),
}
pub trait Crypter { pub trait Crypter {
fn crypt(&mut self, data: &mut [u8]) -> Result<(), EncryptionError>; fn crypt_u32(&mut self, value: u32) -> u32;
fn crypt(&mut self, data: &mut [u8]) {
let remaining_bytes_count = data.len() % 4;
let dword_length = if remaining_bytes_count > 0 {
data.len() - remaining_bytes_count
} else {
data.len()
};
// encrypt all of the dword-sized data in the given buffer
if dword_length > 0 {
let mut dword: *mut u32 = data.as_mut_ptr().cast();
for _ in 0..(dword_length / 4) {
unsafe {
*dword = self.crypt_u32(*dword);
dword = dword.add(1);
}
}
}
// if there is a remaining 1-3 bytes at the end of the buffer ...
if remaining_bytes_count > 0 {
// copy those 1-3 bytes into a temporary dword buffer
let mut remaining_bytes = [0u8; 4];
remaining_bytes[0..remaining_bytes_count].copy_from_slice(&data[dword_length..]);
// encrypt the temp dword buffer
let dword: *mut u32 = remaining_bytes.as_mut_ptr().cast();
unsafe {
*dword = self.crypt_u32(*dword);
}
// copy those now-encrypted 1-3 bytes back out of the temp buffer
data[dword_length..].copy_from_slice(&remaining_bytes[0..remaining_bytes_count]);
}
}
} }
pub struct GCCrypter { pub struct GCCrypter {
@ -93,14 +120,9 @@ impl GCCrypter {
} }
impl Crypter for GCCrypter { impl Crypter for GCCrypter {
fn crypt(&mut self, data: &mut [u8]) -> Result<(), EncryptionError> { fn crypt_u32(&mut self, mut value: u32) -> u32 {
let data = data.as_mut_slice_of::<u32>()?; value ^= self.next().to_le();
value
for dword in data.iter_mut() {
*dword ^= self.next().to_le();
}
Ok(())
} }
} }
@ -179,21 +201,14 @@ impl PCCrypter {
} }
impl Crypter for PCCrypter { impl Crypter for PCCrypter {
fn crypt(&mut self, data: &mut [u8]) -> Result<(), EncryptionError> { fn crypt_u32(&mut self, mut value: u32) -> u32 {
let data = data.as_mut_slice_of::<u32>()?; value ^= self.next().to_le();
value
for dword in data.iter_mut() {
*dword ^= self.next().to_le();
}
Ok(())
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use claim::*;
use super::*; use super::*;
#[test] #[test]
@ -213,17 +228,17 @@ mod tests {
// encrypt data // encrypt data
let mut encrypter = PCCrypter::new(seed); let mut encrypter = PCCrypter::new(seed);
assert_ok!(encrypter.crypt(&mut buffer)); encrypter.crypt(&mut buffer);
assert_eq!(buffer, encrypted); assert_eq!(buffer, encrypted);
// crypting the same buffer again with the same Crypter instance won't decrypt it // crypting the same buffer again with the same Crypter instance won't decrypt it
let mut temp_buffer = buffer.clone(); let mut temp_buffer = buffer.clone();
assert_ok!(encrypter.crypt(&mut temp_buffer)); encrypter.crypt(&mut temp_buffer);
assert_ne!(temp_buffer, decrypted); assert_ne!(temp_buffer, decrypted);
// crypting the previous buffer with a new Crypter using the same seed, will decrypt it // crypting the previous buffer with a new Crypter using the same seed, will decrypt it
let mut decrypter = PCCrypter::new(seed); let mut decrypter = PCCrypter::new(seed);
assert_ok!(decrypter.crypt(&mut buffer)); decrypter.crypt(&mut buffer);
assert_eq!(buffer, decrypted); assert_eq!(buffer, decrypted);
} }
@ -244,64 +259,48 @@ mod tests {
// encrypt data // encrypt data
let mut encrypter = GCCrypter::new(seed); let mut encrypter = GCCrypter::new(seed);
assert_ok!(encrypter.crypt(&mut buffer)); encrypter.crypt(&mut buffer);
assert_eq!(buffer, encrypted); assert_eq!(buffer, encrypted);
// crypting the same buffer again with the same Crypter instance won't decrypt it // crypting the same buffer again with the same Crypter instance won't decrypt it
let mut temp_buffer = buffer.clone(); let mut temp_buffer = buffer.clone();
assert_ok!(encrypter.crypt(&mut temp_buffer)); encrypter.crypt(&mut temp_buffer);
assert_ne!(temp_buffer, decrypted); assert_ne!(temp_buffer, decrypted);
// crypting the previous buffer with a new Crypter using the same seed, will decrypt it // crypting the previous buffer with a new Crypter using the same seed, will decrypt it
let mut decrypter = GCCrypter::new(seed); let mut decrypter = GCCrypter::new(seed);
assert_ok!(decrypter.crypt(&mut buffer)); decrypter.crypt(&mut buffer);
assert_eq!(buffer, decrypted); assert_eq!(buffer, decrypted);
} }
#[test] #[test]
fn pc_crypt_non_dword_sized_data_returns_error() { fn pc_crypt_non_dword_sized_data_works() {
let mut crypter = PCCrypter::new(0x12345678); let mut crypter = PCCrypter::new(0x12345678);
// too small. 3 bytes, not dword-sized // 3 bytes
let mut bad_data = [0x01, 0x02, 0x03]; let mut first = [0x01, 0x02, 0x03];
assert_matches!( crypter.crypt(&mut first);
crypter.crypt(&mut bad_data), assert_eq!(first, [0x97, 0x89, 0xeb]);
Err(EncryptionError::InputDataCastingError(_))
);
// too big. 5 bytes, also not dword-sized // 5 bytes
let mut bad_data = [0x01, 0x02, 0x03, 0x04, 0x05]; let mut second = [0x01, 0x02, 0x03, 0x04, 0x05];
assert_matches!( crypter.crypt(&mut second);
crypter.crypt(&mut bad_data), assert_eq!(second, [0xb8, 0x62, 0x33, 0xcf, 0x6d]);
Err(EncryptionError::InputDataCastingError(_))
);
// good. dword-sized
let mut good_data = [0x01, 0x02, 0x03, 0x04];
assert_ok!(crypter.crypt(&mut good_data));
} }
#[test] #[test]
fn gc_crypt_non_dword_sized_data_returns_error() { fn gc_crypt_non_dword_sized_data_returns_error() {
let mut crypter = GCCrypter::new(0x12345678); let mut crypter = GCCrypter::new(0x12345678);
// too small. 3 bytes, not dword-sized // 3 bytes
let mut bad_data = [0x01, 0x02, 0x03]; let mut first = [0x01, 0x02, 0x03];
assert_matches!( crypter.crypt(&mut first);
crypter.crypt(&mut bad_data), assert_eq!(first, [0xc3, 0xe0, 0x31]);
Err(EncryptionError::InputDataCastingError(_))
);
// too big. 5 bytes, also not dword-sized // 5 bytes
let mut bad_data = [0x01, 0x02, 0x03, 0x04, 0x05]; let mut second = [0x01, 0x02, 0x03, 0x04, 0x05];
assert_matches!( crypter.crypt(&mut second);
crypter.crypt(&mut bad_data), assert_eq!(second, [0x4a, 0x2f, 0xcd, 0xdf, 0xbc]);
Err(EncryptionError::InputDataCastingError(_))
);
// good. dword-sized
let mut good_data = [0x01, 0x02, 0x03, 0x04];
assert_ok!(crypter.crypt(&mut good_data));
} }
#[test] #[test]
@ -323,19 +322,19 @@ mod tests {
let mut encrypter = PCCrypter::new(seed); let mut encrypter = PCCrypter::new(seed);
let mut first_buffer = first_decrypted.clone(); let mut first_buffer = first_decrypted.clone();
assert_ok!(encrypter.crypt(&mut first_buffer)); encrypter.crypt(&mut first_buffer);
assert_eq!(first_encrypted, first_buffer); assert_eq!(first_encrypted, first_buffer);
let mut second_buffer = second_decrypted.clone(); let mut second_buffer = second_decrypted.clone();
assert_ok!(encrypter.crypt(&mut second_buffer)); encrypter.crypt(&mut second_buffer);
assert_eq!(second_encrypted, second_buffer); assert_eq!(second_encrypted, second_buffer);
let mut decrypter = PCCrypter::new(seed); let mut decrypter = PCCrypter::new(seed);
assert_ok!(decrypter.crypt(&mut first_buffer)); decrypter.crypt(&mut first_buffer);
assert_eq!(first_decrypted, first_buffer); assert_eq!(first_decrypted, first_buffer);
assert_ok!(decrypter.crypt(&mut second_buffer)); decrypter.crypt(&mut second_buffer);
assert_eq!(second_decrypted, second_buffer); assert_eq!(second_decrypted, second_buffer);
} }
@ -358,19 +357,19 @@ mod tests {
let mut encrypter = GCCrypter::new(seed); let mut encrypter = GCCrypter::new(seed);
let mut first_buffer = first_decrypted.clone(); let mut first_buffer = first_decrypted.clone();
assert_ok!(encrypter.crypt(&mut first_buffer)); encrypter.crypt(&mut first_buffer);
assert_eq!(first_encrypted, first_buffer); assert_eq!(first_encrypted, first_buffer);
let mut second_buffer = second_decrypted.clone(); let mut second_buffer = second_decrypted.clone();
assert_ok!(encrypter.crypt(&mut second_buffer)); encrypter.crypt(&mut second_buffer);
assert_eq!(second_encrypted, second_buffer); assert_eq!(second_encrypted, second_buffer);
let mut decrypter = GCCrypter::new(seed); let mut decrypter = GCCrypter::new(seed);
assert_ok!(decrypter.crypt(&mut first_buffer)); decrypter.crypt(&mut first_buffer);
assert_eq!(first_decrypted, first_buffer); assert_eq!(first_decrypted, first_buffer);
assert_ok!(decrypter.crypt(&mut second_buffer)); decrypter.crypt(&mut second_buffer);
assert_eq!(second_decrypted, second_buffer); assert_eq!(second_decrypted, second_buffer);
} }
@ -496,11 +495,11 @@ mod tests {
let mut buffer = decrypted.clone(); let mut buffer = decrypted.clone();
let mut encrypter = PCCrypter::new(seed); let mut encrypter = PCCrypter::new(seed);
assert_ok!(encrypter.crypt(&mut buffer)); encrypter.crypt(&mut buffer);
assert_eq!(encrypted, buffer); assert_eq!(encrypted, buffer);
let mut decrypter = PCCrypter::new(seed); let mut decrypter = PCCrypter::new(seed);
assert_ok!(decrypter.crypt(&mut buffer)); decrypter.crypt(&mut buffer);
assert_eq!(decrypted, buffer); assert_eq!(decrypted, buffer);
} }
@ -626,11 +625,11 @@ mod tests {
let mut buffer = decrypted.clone(); let mut buffer = decrypted.clone();
let mut encrypter = GCCrypter::new(seed); let mut encrypter = GCCrypter::new(seed);
assert_ok!(encrypter.crypt(&mut buffer)); encrypter.crypt(&mut buffer);
assert_eq!(encrypted, buffer); assert_eq!(encrypted, buffer);
let mut decrypter = GCCrypter::new(seed); let mut decrypter = GCCrypter::new(seed);
assert_ok!(decrypter.crypt(&mut buffer)); decrypter.crypt(&mut buffer);
assert_eq!(decrypted, buffer); assert_eq!(decrypted, buffer);
} }
} }