use std::convert::TryInto;
use std::time::SystemTime;
use rand_core::{SeedableRng, RngCore};
use rand_chacha::ChaCha12Rng;
pub struct SecureRng(ChaCha12Rng);
impl Default for SecureRng {
fn default() -> Self {
let time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
Self::with_seed(time.as_millis() as u64)
}
}
impl SecureRng {
pub fn with_seed(seed: u64) -> Self {
let inner = ChaCha12Rng::seed_from_u64(seed);
SecureRng(inner)
}
pub fn with_safe_seed<S, K>(encrypted: S, key: K) -> Self
where S: AsRef<[u8]>,
K: AsRef<[u8]>,
{
let unencrypted = xor_encrypt(encrypted, key).unwrap();
let seed = u64::from_le_bytes(unencrypted.as_slice().try_into().unwrap());
Self::with_seed(seed)
}
pub fn with_confusion_seed<S, K>(encrypted: S, key: K) -> Self
where S: AsRef<[u8]>,
K: AsRef<[u8]>,
{
let unencrypted = xor_unencrypt_clarity(encrypted, key).unwrap();
let seed = u64::from_le_bytes(unencrypted.as_slice().try_into().unwrap());
Self::with_seed(seed)
}
#[inline]
pub fn get_u32(&mut self) -> u32 {
self.0.next_u32()
}
#[inline]
pub fn get_u64(&mut self) -> u64 {
self.0.next_u64()
}
}
#[inline]
pub fn xor_encrypt<T, K>(data: T, key: K) -> Result<Vec<u8>, ()>
where
T: AsRef<[u8]>,
K: AsRef<[u8]>,
{
let data = data.as_ref();
let key = key.as_ref();
if key.as_ref().len() < 8 {
return Err(());
}
let encrypted = data
.iter()
.enumerate()
.map(|(i, &byte)| byte ^ key[i % key.len()])
.collect();
Ok(encrypted)
}
#[inline]
pub fn xor_encrypt_confusion<T, K>(data: T, key: K) -> Result<Vec<u8>, ()>
where
T: AsRef<[u8]>,
K: AsRef<[u8]>,
{
let encrypt = xor_encrypt(data, key)?;
let len = encrypt.len();
if len % 2 != 0 {
return Err(());
}
let half_len = len / 2;
let mut confused = Vec::with_capacity(len);
confused.resize(len, 0);
for i in 0..len {
if i % 2 != 0 {
confused[i] = encrypt[i];
continue;
} else if i < half_len {
let j = i + half_len;
confused[j] = encrypt[i];
confused[i] = encrypt[j];
}
}
Ok(confused)
}
#[inline]
pub fn xor_unencrypt_clarity<T, K>(data: T, key: K) -> Result<Vec<u8>, ()>
where
T: AsRef<[u8]>,
K: AsRef<[u8]>,
{
let encrypt = data.as_ref();
let len = encrypt.len();
if len % 2 != 0 {
return Err(());
}
let half_len = len / 2;
let mut clarified = Vec::with_capacity(len);
clarified.resize(len, 0);
for i in 0..len {
if i % 2 != 0 {
clarified[i] = encrypt[i];
continue;
} else if i < half_len {
let j = i + half_len;
clarified[j] = encrypt[i];
clarified[i] = encrypt[j];
}
}
let unencrypt = xor_encrypt(clarified, key)?;
Ok(unencrypt)
}