use std::{any::TypeId, marker::PhantomData, mem};
use err::XRCResult;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
mod cipher;
mod test;
mod v2;
pub mod err;
pub trait XrcVersion {}
pub struct V1;
impl XrcVersion for V1 {}
pub struct V2;
impl XrcVersion for V2 {}
#[cfg(target_pointer_width = "64")]
pub struct XORCryptor<T> {
cipher: cipher::Cipher,
e_table: Vec<u16>,
d_table: Vec<u16>,
raw_seed: usize,
_marker: PhantomData<T>,
}
#[cfg(target_pointer_width = "64")]
impl<T: XrcVersion> XORCryptor<T> {
fn generate_table(e_table: &mut Vec<u16>, d_table: &mut Vec<u16>) {
let (mut count, mut shift, mut value, mut bit_mask): (u16, u16, u16, u16);
let (mut mask, mut mode) = (0u16, 0u16);
for i in 0..=255 as u16 {
(count, shift, value) = (4, 0, i);
while count != 0 {
bit_mask = value & 3;
let mask_shift: u16 = (bit_mask > 1).into();
let mode_shift: u16 = (bit_mask == 0 || bit_mask == 3).into();
mask |= mask_shift << shift;
mode |= mode_shift << shift;
count -= 1;
shift += 1;
value >>= 2;
}
mask = (mode << 8) | mask;
e_table[i as usize] = mask;
d_table[mask as usize] = i;
(mask, mode) = (0, 0);
}
}
#[inline]
fn encrypt_byte(&self, val: usize) -> usize {
self.e_table[val & 0xFF] as usize
| (self.e_table[(val >> 0x8) & 0xFF] as usize) << 0x4
| (self.e_table[(val >> 0x10) & 0xFF] as usize) << 0x10
| (self.e_table[(val >> 0x18) & 0xFF] as usize) << 0x14
| (self.e_table[(val >> 0x20) & 0xFF] as usize) << 0x20
| (self.e_table[(val >> 0x28) & 0xFF] as usize) << 0x24
| (self.e_table[(val >> 0x30) & 0xFF] as usize) << 0x30
| (self.e_table[(val >> 0x38) & 0xFF] as usize) << 0x34
}
#[inline]
fn decrypt_byte(&self, val: usize) -> usize {
self.d_table[val & 0x0F0F] as usize
| (self.d_table[(val >> 0x4) & 0x0F0F] as usize) << 0x8
| (self.d_table[(val >> 0x10) & 0x0F0F] as usize) << 0x10
| (self.d_table[(val >> 0x14) & 0x0F0F] as usize) << 0x18
| (self.d_table[(val >> 0x20) & 0x0F0F] as usize) << 0x20
| (self.d_table[(val >> 0x24) & 0x0F0F] as usize) << 0x28
| (self.d_table[(val >> 0x30) & 0x0F0F] as usize) << 0x30
| (self.d_table[(val >> 0x34) & 0x0F0F] as usize) << 0x38
}
pub fn get_cipher(&self) -> &[usize] {
self.cipher.get_cipher()
}
}
#[cfg(target_pointer_width = "64")]
impl XORCryptor<V1> {
pub fn new(key: &str) -> XRCResult<Self> {
let cipher = cipher::Cipher::from(key)?;
Ok(XORCryptor::init(cipher))
}
pub fn new_bytes(key: &[u8]) -> XRCResult<Self> {
let cipher = cipher::Cipher::from_bytes(key)?;
Ok(XORCryptor::init(cipher))
}
fn init(cipher: cipher::Cipher) -> Self {
let (mut e_table, mut d_table) = (vec![0u16; 256], vec![0u16; 0xF10]);
Self::generate_table(&mut e_table, &mut d_table);
XORCryptor {
cipher,
e_table,
d_table,
raw_seed: 0,
_marker: PhantomData,
}
}
fn encrypt_buffer(&self, src: &mut Vec<usize>, b_len: usize) {
let mut byte_count = b_len;
let odd = b_len % 8 != 0;
let length = src.len() - if odd { 1 } else { 0 };
let src_ptr = Ptr(src.as_mut_ptr());
byte_count -= 8 * length;
(0..length).into_par_iter().for_each(move |i| unsafe {
let val = *{ src_ptr }.0.add(i);
let mut lxi = self.encrypt_byte(val);
lxi = ((lxi & 0x00FF_00FF_00FF_00FF) << 8) ^ lxi;
*{ src_ptr }.0.add(i) = lxi ^ self.cipher.get_cipher_byte(i);
});
if odd {
let (val, mut shift) = (src[length], 0usize);
let mut lxi = 0usize;
while byte_count > 1 {
lxi |= (self.e_table[(val >> shift) & 0xFF] as usize) << shift
| ((self.e_table[((val >> 8) >> shift) & 0xFF] as usize) << 4) << shift;
shift += 16;
byte_count -= 2;
}
let mut mm = self.e_table[(val >> shift) & 0xFF] as usize;
mm = ((mm & 0xF00) >> 8) | ((mm & 0xF) << 4);
mm ^= mm >> 4;
lxi |= mm << shift;
lxi = ((lxi & 0x00FF_00FF_00FF_00FF) << 8) ^ lxi;
src[length] = lxi ^ self.cipher.get_cipher_byte(length);
}
}
fn decrypt_buffer(&self, src: &mut Vec<usize>, b_len: usize) {
let mut byte_count = b_len;
let odd = b_len % 8 != 0;
let length = src.len() - if odd { 1 } else { 0 };
let src_ptr = Ptr(src.as_mut_ptr());
byte_count -= 8 * length;
(0..length).into_par_iter().for_each(move |i| unsafe {
*{ src_ptr }.0.add(i) ^= self.cipher.get_cipher_byte(i);
let val = *{ src_ptr }.0.add(i);
let xi = ((val & 0x00FF_00FF_00FF_00FF) << 8) ^ val;
*{ src_ptr }.0.add(i) = self.decrypt_byte(xi);
});
if odd {
src[length] ^= self.cipher.get_cipher_byte(length);
let xi = ((src[length] & 0x00FF_00FF_00FF_00FF) << 8) ^ src[length];
let (mut lxi, mut shift) = (0usize, 0usize);
while byte_count > 1 {
lxi |= (self.d_table[(xi >> shift) & 0x0F0F] as usize) << shift
| (self.d_table[(xi >> shift >> 4) & 0x0F0F] as usize) << 8 << shift;
shift += 0x10;
byte_count -= 2;
}
let mut mm = (xi >> shift) & 0xFF;
mm ^= mm >> 4;
mm = ((mm & 0xF0) >> 4) | ((mm & 0xF) << 8);
lxi |= (self.d_table[mm] as usize) << shift;
src[length] = lxi;
}
}
#[deprecated]
pub fn encrypt_vec(&self, buffer: Vec<u8>) -> Vec<u8> {
if buffer.is_empty() {
return vec![];
}
let b_len = buffer.len();
let mut src = transmute_buffer::<u8, usize>(buffer, 0, 0, Version::V1);
self.encrypt_buffer(&mut src, b_len);
transmute_buffer(src, b_len, 0, Version::V1)
}
#[deprecated]
pub fn decrypt_vec(&self, buffer: Vec<u8>) -> Vec<u8> {
if buffer.is_empty() {
return vec![];
}
let b_len = buffer.len();
let mut src = transmute_buffer::<u8, usize>(buffer, 0, 0, Version::V1);
self.decrypt_buffer(&mut src, b_len);
transmute_buffer(src, b_len, 0, Version::V1)
}
}
#[derive(Copy, Clone)]
struct Ptr<T>(*mut T);
unsafe impl<T> Send for Ptr<T> {}
unsafe impl<T> Sync for Ptr<T> {}
enum Version {
V1,
V2,
}
fn transmute_buffer<T, R>(mut buffer: Vec<T>, b_len: usize, default: T, version: Version) -> Vec<R>
where
T: Sized + Clone + 'static,
R: Sized + 'static,
{
let (t, r) = (TypeId::of::<T>(), TypeId::of::<R>());
let (t8, t_usize) = (TypeId::of::<u8>(), TypeId::of::<usize>());
if (t != t8 || r != t_usize) && (t != t_usize || r != t8) {
return vec![];
}
let from_u8_usize = t == t8 && r == t_usize;
let len = buffer.len();
let (upper, rem) = (len + 8, len % 8);
let rem_a = upper % 8;
let length = if from_u8_usize {
let rz: usize = (rem == 0).into();
((len * rz) + (upper * (1 - rz))) / 8
} else {
len * 8
};
if from_u8_usize {
let addition = if rem == 0 { 0 } else { upper - rem_a - len };
buffer.resize(
buffer.len()
+ addition
+ match version {
Version::V1 => 0,
Version::V2 => 2,
},
default,
);
}
let mut data: Vec<R>;
unsafe {
let mutptr = buffer.as_ptr() as *mut R;
mem::forget(buffer);
data = Vec::from_raw_parts(mutptr, length, length)
}
if !from_u8_usize && b_len != 0 {
data.truncate(b_len);
}
data
}