use std::num::Wrapping;
use std::ops::Range;
use std::vec::Vec;
use byteorder::ByteOrder;
use byteorder::LittleEndian;
use byteorder::WriteBytesExt;
static INDEX_KEY: &str = "#:AhppdV-!PEfz&}[]Nv?6w4guU%dF5.fq:n*-qGuhBJJBm&?2tPy!geW/+k#pG?";
fn get_key_at(pos: usize) -> u8 {
INDEX_KEY.as_bytes()[pos % (INDEX_KEY.len())]
}
pub fn decrypt_index_item_file_length(item_index: u32, ciphertext: u32) -> u32 {
let decrypted = !item_index ^ ciphertext ^ 0xE10B73F4;
if ::DEBUG {
println!("File length: {:X} = {:X} ^ {:X} ^ {:X}", decrypted, !item_index, ciphertext, 0x15091984);
}
decrypted
}
pub fn decrypt_index_item_filename(ciphertext: &[u8], key: u8) -> (Vec<u8>, u32) {
let mut buffer: Vec<u8> = Vec::with_capacity(100);
let mut idx = 0;
loop {
let c = ciphertext[idx as usize] ^ !key ^ get_key_at(idx);
if ::DEBUG {
println!("{:X} ({}) = {:X} ^ {:X} ^ {:X}", c, c as char, ciphertext[idx as usize], !key, get_key_at(idx));
}
idx += 1;
if c == 0 {
break;
}
buffer.push(c);
}
(buffer, idx as u32)
}
static FILE_KEY: Wrapping<u64> = Wrapping(0x8FEB2A6740A6920E);
pub fn decrypt_file(ciphertext: &[u8], length: usize, verbose: bool) -> Vec<u8> {
let mut plaintext = Vec::with_capacity(ciphertext.len());
let padded_length = ciphertext.len() + 7 & !7;
assert!(padded_length % 8 == 0);
assert!(padded_length < ciphertext.len() + 8);
let mut edi: u32 = 0;
let mut esi = 0;
let mut eax;
let mut edx;
for _ in 0..padded_length/8 {
let prod = (FILE_KEY * Wrapping((!edi) as u64)).0;
if verbose {
println!("prod: {:X}", prod);
}
eax = prod as u32;
edx = (prod >> 32) as u32;
if verbose {
println!("eax: {:X}", eax);
println!("edx: {:X}", edx);
}
eax ^= read_padded_u32(&ciphertext, esi..esi + 4);
if verbose {
println!("eax: {:X}", eax);
}
edi += 8;
let _edx = read_padded_u32(&ciphertext, esi + 4..esi + 8);
if verbose {
println!("_edx {:X}", _edx);
}
edx ^= _edx;
if verbose {
println!("edx {:X}", edx);
}
plaintext.write_u32::<LittleEndian>(eax).unwrap();
if verbose {
println!("{:X}", edx);
}
plaintext.write_u32::<LittleEndian>(edx).unwrap();
esi += 8;
}
plaintext.truncate(length);
plaintext
}
fn read_padded_u32(source: &[u8], range: Range<usize>) -> u32 {
if range.end <= source.len() {
LittleEndian::read_u32(&source[range])
} else {
let mut v = Vec::with_capacity(4);
if range.start < source.len() {
v.extend_from_slice(&source[range.start..source.len()]);
}
v.resize(4, 0);
debug_assert!(v.len() == 4);
LittleEndian::read_u32(&v)
}
}