extern crate proc_macro;
extern crate proc_macro2;
extern crate quote;
extern crate rand;
#[cfg(test)]
#[macro_use(expect)]
extern crate expectest;
use proc_macro::{TokenStream, TokenTree};
use proc_macro2::Literal;
use quote::quote;
use rand::{rngs::OsRng, RngCore};
use std::env;
mod xor;
lazy_static::lazy_static! {
static ref RAND_SPELL: [u8; 64] = {
let mut key = [0u8; 64];
OsRng.fill_bytes(&mut key);
key
};
}
#[inline(always)]
fn get_magic_spell() -> Vec<u8> {
match env::var("LITCRYPT_ENCRYPT_KEY") {
Ok(key) => key.as_bytes().to_vec(),
Err(_) => {
RAND_SPELL.to_vec()
}
}
}
#[proc_macro]
pub fn use_litcrypt(_tokens: TokenStream) -> TokenStream {
let magic_spell = get_magic_spell();
let encdec_func = quote! {
pub mod litcrypt_internal {
pub fn xor(source: &[u8], key: &[u8]) -> Vec<u8> {
match key.len() {
0 => source.into(),
1 => xor_with_byte(source, key[0]),
_ => {
let key_iter = InfiniteByteIterator::new(key);
source.iter().zip(key_iter).map(|(&a, b)| a ^ b).collect()
}
}
}
pub fn xor_with_byte(source: &[u8], byte: u8) -> Vec<u8> {
source.iter().map(|&a| a ^ byte).collect()
}
struct InfiniteByteIterator<'a> {
bytes: &'a [u8],
index: usize,
}
impl<'a> InfiniteByteIterator<'a> {
pub fn new(bytes: &'a [u8]) -> InfiniteByteIterator<'a> {
InfiniteByteIterator {
bytes: bytes,
index: 0,
}
}
}
impl<'a> Iterator for InfiniteByteIterator<'a> {
type Item = u8;
fn next(&mut self) -> Option<u8> {
let byte = self.bytes[self.index];
self.index = next_index(self.index, self.bytes.len());
Some(byte)
}
}
fn next_index(index: usize, count: usize) -> usize {
if index + 1 < count {
index + 1
} else {
0
}
}
pub fn decrypt_bytes(encrypted: &[u8], encrypt_key: &[u8]) -> String {
let decrypted = xor(&encrypted[..], &encrypt_key);
String::from_utf8(decrypted).unwrap()
}
}
};
let result = {
let ekey = xor::xor(&magic_spell, b"l33t");
let ekey = Literal::byte_string(&ekey);
quote! {
static LITCRYPT_ENCRYPT_KEY: &'static [u8] = #ekey;
#encdec_func
}
};
result.into()
}
#[proc_macro]
pub fn lc(tokens: TokenStream) -> TokenStream {
let mut something = String::from("");
for tok in tokens {
something = match tok {
TokenTree::Literal(lit) => lit.to_string(),
_ => "<unknown>".to_owned(),
}
}
something = String::from(&something[1..something.len() - 1]);
encrypt_string(something)
}
#[proc_macro]
pub fn lc_env(tokens: TokenStream) -> TokenStream {
let mut var_name = String::from("");
for tok in tokens {
var_name = match tok {
TokenTree::Literal(lit) => lit.to_string(),
_ => "<unknown>".to_owned(),
}
}
var_name = String::from(&var_name[1..var_name.len() - 1]);
encrypt_string(env::var(var_name).unwrap_or(String::from("unknown")))
}
fn encrypt_string(something: String) -> TokenStream {
let magic_spell = get_magic_spell();
let encrypt_key = xor::xor(&magic_spell, b"l33t");
let encrypted = xor::xor(something.as_bytes(), &encrypt_key);
let encrypted = Literal::byte_string(&encrypted);
let result = quote! {
crate::litcrypt_internal::decrypt_bytes(#encrypted, crate::LITCRYPT_ENCRYPT_KEY)
};
result.into()
}