extern crate proc_macro;
extern crate proc_macro2;
extern crate quote;
#[cfg(test)]
#[macro_use(expect)]
extern crate expectest;
use proc_macro::{TokenStream, TokenTree};
use proc_macro2::Literal;
use quote::quote;
use std::env;
mod xor;
#[inline(always)]
fn get_magic_spell() -> String {
env::var("LITCRYPT_ENCRYPT_KEY").unwrap_or_else(|_| {
panic!("LITCRYPT_ENCRYPT_KEY environment variable not set.")
})
}
#[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.as_bytes(), 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]);
let magic_spell = get_magic_spell();
let encrypt_key = xor::xor(magic_spell.as_bytes(), 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()
}