#[doc(hidden)] pub use include_crypt_codegen as codegen;
#[doc(hidden)] pub use include_crypt_crypto as crypto;
#[doc(hidden)] pub use obfstr;
use crate::obfstr::{random, ObfString};
use crypto::{
aes::{aes_decrypt, AES_KEY_LEN, AES_NONCE_LEN},
key::EncryptionKey,
xor::{xor, XOR_KEY_LEN},
};
use std::{
collections::hash_map::DefaultHasher,
hash::{Hash, Hasher},
string::FromUtf8Error,
};
pub enum EncryptionType {
Xor(ObfString<[u8; XOR_KEY_LEN * 2]>),
Aes(ObfString<[u8; AES_KEY_LEN * 2]>, ObfString<[u8; AES_NONCE_LEN * 2]>),
}
pub struct EncryptedFile {
buffer: &'static [u8],
enc_type: EncryptionType,
}
impl EncryptedFile {
pub const fn new(buffer: &'static [u8], enc_type: EncryptionType) -> Self { Self { buffer, enc_type } }
#[inline(always)]
pub fn decrypt(&self) -> Vec<u8> {
let buffer = match &self.enc_type {
EncryptionType::Xor(key) => {
let mut buffer = self.buffer.to_vec();
let _ = EncryptionKey::new(key.deobfuscate(random!(u16) as usize).as_str(), XOR_KEY_LEN)
.map(|key| xor(buffer.as_mut_slice(), key));
buffer.to_vec()
}
EncryptionType::Aes(key, nonce) => {
let mut buffer = self.buffer.to_vec();
let _ = EncryptionKey::new(key.deobfuscate(random!(u16) as usize).as_str(), AES_KEY_LEN).map(|key| {
EncryptionKey::new(nonce.deobfuscate(random!(u16) as usize).as_str(), AES_NONCE_LEN).map(|nonce| {
let _ = aes_decrypt(buffer.as_mut_slice(), key, nonce);
})
});
buffer
}
};
#[cfg(feature = "compression")]
{
use std::io::Read;
let mut decompressed = Vec::new();
let mut decoder = libflate::deflate::Decoder::new(std::io::Cursor::new(buffer));
decoder
.read_to_end(&mut decompressed)
.expect("The embedded deflate buffer was corrupted");
decompressed
}
#[cfg(not(feature = "compression"))]
{
buffer
}
}
#[inline(always)]
pub fn decrypt_str(&self) -> Result<String, FromUtf8Error> { String::from_utf8(self.decrypt()) }
}
#[macro_export]
macro_rules! include_crypt {
(XOR, $path:expr) => {{
let (key, data) = $crate::codegen::encrypt_xor!($path);
$crate::EncryptedFile::new(data, $crate::EncryptionType::Xor(key))
}};
(XOR, $path:expr, $key:expr) => {{
let (key, data) = $crate::codegen::encrypt_xor!($path, $key);
$crate::EncryptedFile::new(data, $crate::EncryptionType::Xor(key))
}};
(AES, $path:expr) => {{
let (key, nonce, data) = $crate::codegen::encrypt_aes!($path);
$crate::EncryptedFile::new(data, $crate::EncryptionType::Aes(key, nonce))
}};
(AES, $path:expr, $key:expr) => {{
let (key, nonce, data) = $crate::codegen::encrypt_aes!($path, $key);
$crate::EncryptedFile::new(data, $crate::EncryptionType::Aes(key, nonce))
}};
($path:expr) => {
$crate::include_crypt!(XOR, $path)
};
($path:expr, $key:expr) => {
$crate::include_crypt!(XOR, $path, $key)
};
}
#[derive(Clone)]
pub struct EncryptedFolder<'a> {
#[doc(hidden)]
pub files: &'a [(&'static str, EncryptedFile)],
}
impl<'a> EncryptedFolder<'a> {
pub fn get(&self, file_path: &str) -> Option<&EncryptedFile> {
let file_path = {
let path = file_path.replace("\\", "/");
let mut hasher = DefaultHasher::new();
path.hash(&mut hasher);
hasher.finish().to_string()
};
for (path, file) in self.files {
if *path == file_path {
return Some(file);
}
}
None
}
}
#[macro_export]
macro_rules! include_dir {
(XOR, $path:expr) => {
$crate::EncryptedFolder {
files: &$crate::codegen::include_files!("XOR", $path),
}
};
(AES, $path:expr) => {
$crate::EncryptedFolder {
files: &$crate::codegen::include_files!("AES", $path),
}
};
($path:expr) => {
$crate::include_dir!(XOR, $path)
};
}