diff --git a/encr_data.bin b/encr_data.bin new file mode 100644 index 0000000..adedf40 Binary files /dev/null and b/encr_data.bin differ diff --git a/src/main.rs b/src/main.rs index f820531..72767df 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,9 @@ use std::io::{Read, Seek, SeekFrom}; use std::fs::File; use std::default::Default; +use std::mem::transmute; + +use byteorder::{ReadBytesExt, LittleEndian}; #[derive(Default)] pub struct NDSCartridgeHeader { @@ -45,19 +48,62 @@ pub fn blowfish_nds(v: &mut u64, kbuf: &[u32], enc: bool) { } // Swap + P-array[16,17] XOR - *v = ((x ^ kbuf[koff]) as u64) | (((y ^ kbuf[1 + koff]) as u64) << 32); + *v = ((y ^ kbuf[koff]) as u64) | (((x ^ kbuf[1 + koff]) as u64) << 32); +} + +/* Applies a series of arbitrary manipulations on the P-array and S-boxes + depending on the title key. +*/ +pub fn apply_keycode(tk: &mut [u32; 3], kbuf: &mut [u32]) { + // The two encrypt steps overlap each other + let tk0ptr = unsafe { transmute::<&mut u32, &mut u64>(&mut tk[0]) }; + let tk1ptr = unsafe { transmute::<&mut u32, &mut u64>(&mut tk[1]) }; + let mut scratch: u64 = 0; + + blowfish_nds(tk1ptr, kbuf, true); + blowfish_nds(tk0ptr, kbuf, true); + + for i in 0..12 { + kbuf[i] = kbuf[i] ^ kbuf[i % 2].swap_bytes(); + } + + for i in (0..131).step_by(2) { + blowfish_nds(&mut scratch, kbuf, true); + kbuf[i] = unsafe { *transmute::<*const u64, *const u32>(&scratch as *const u64).offset(1) }; + kbuf[i + 1] = unsafe { *transmute::<*const u64, *const u32>(&scratch as *const u64) }; + } +} + +pub fn load_encr_data(encr_data: &mut R) -> Result<[u32; 262], &'static str> { + // let data_len = encr_data.seek(SeekFrom::End(0)).map_err(|_| { "Seek failed on encryption binary." })?; + encr_data.seek(SeekFrom::Start(0)).map_err(|_| { "Seek failed on encryption binary." })?; + + let mut contents: [u32; 262] = [0; 262]; + for i in &mut contents { + *i = encr_data.read_u32::().unwrap(); + } + + Ok(contents) } fn main() { let mut ndsfile = File::open("pokemon.nds").unwrap(); - let encr_data = File::open("encr_data.bin").unwrap(); + let mut encr_data = File::open("encr_data.bin").unwrap(); - let titlecode = NDSCartridgeHeader::parse_nds(&mut ndsfile).gamecode; - let titlecode4: u32 = u32::from_le_bytes(titlecode); + let mut encr = load_encr_data(&mut encr_data).unwrap(); - let keycode: [u32; 3] = [ + let ndshdr = NDSCartridgeHeader::parse_nds(&mut ndsfile); + let titlestr: String = String::from_utf8_lossy(&ndshdr.gametitle).into_owned(); + let titlecode4: u32 = u32::from_le_bytes(ndshdr.gamecode); + + let mut keycode: [u32; 3] = [ titlecode4, titlecode4 >> 1, titlecode4 << 1, ]; + + apply_keycode(&mut keycode, &mut encr); + + println!("Game title: {}", titlestr); + println!("Game code: {:#06x}", titlecode4); }