Skip to content

Instantly share code, notes, and snippets.

@XMPPwocky
Created December 20, 2014 07:14
Show Gist options
  • Save XMPPwocky/e7689cd19e78cf46390b to your computer and use it in GitHub Desktop.
Save XMPPwocky/e7689cd19e78cf46390b to your computer and use it in GitHub Desktop.
use core;
use core::prelude::*;
use collections;
pub struct ObfuscatedString {
crypted: &'static [u8],
key: &'static [u8]
}
impl ObfuscatedString {
pub fn dec_into(&self, dest: &mut [u8]) {
let &ObfuscatedString { crypted, key } = self;
for (d, (c, k)) in dest.iter_mut().zip(crypted.iter().zip(key.iter())) {
*d = *c ^ *k;
}
}
pub fn dec_vec(&self) -> collections::vec::Vec<u8> {
let len = self.crypted.len();
let mut v = collections::vec::Vec::with_capacity(len);
unsafe {
// safe because of with_capacity
v.set_len(len);
}
self.dec_into(v.as_mut_slice());
v
}
pub fn dec(&self) -> collections::string::String {
// this is safe, because all constructors of ObfuscatedString
// are unsafe; thus the invariant that decryption produces valid UTF-8
// is maintained in safe code
unsafe {
collections::string::raw::from_utf8(self.dec_vec())
}
}
}
impl core::cmp::PartialEq<str> for ObfuscatedString {
fn eq(&self, other: &str) -> bool {
let decrypted = self.crypted.iter().zip(self.key.iter()).map(|(&a, &b)| a ^ b);
core::iter::order::eq(decrypted, other.bytes())
}
}
impl core::cmp::PartialEq<ObfuscatedString> for str {
fn eq(&self, other: &ObfuscatedString) -> bool {
other == self
}
}
impl<'a> core::cmp::PartialEq<ObfuscatedString> for &'a str {
fn eq(&self, other: &ObfuscatedString) -> bool {
other == *self
}
}
pub unsafe fn construct(crypted: &'static [u8], key: &'static [u8]) -> ObfuscatedString {
ObfuscatedString {
crypted: crypted,
key: key
}
}
#![crate_type="dylib"]
#![feature(plugin_registrar)]
extern crate syntax;
extern crate rustc;
use syntax::codemap::Span;
use syntax::parse::{str_lit, token};
use syntax::ast;
use syntax::ast::{Expr, Lit_, TokenTree, TtToken};
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacExpr};
use syntax::ext::build::AstBuilder; // trait for expr_uint
use syntax::ptr::P;
use rustc::plugin::Registry;
fn crypt(s: &str) -> (Vec<u8>, Vec<u8>) {
use std::rand;
use std::rand::Rng;
let s = s.as_bytes();
let mut rng = rand::task_rng();
let mut key = Vec::from_elem(s.len(), 0);
rng.fill_bytes(key.as_mut_slice());
let mut crypted = s.to_vec();
for (c, k) in crypted.iter_mut().zip(key.iter()) {
*c = *c ^ *k;
}
(crypted, key)
}
fn construct_binlit(cx: &mut ExtCtxt, sp: Span, bytes: Vec<u8>) -> P<Expr> {
let rcbytes = std::rc::Rc::new(bytes);
cx.expr_lit(sp, Lit_::LitBinary(rcbytes))
}
fn construct_call(cx: &mut ExtCtxt, sp: Span, crypted: Vec<u8>, key: Vec<u8>) -> P<Expr>
{
let crypted_expr = construct_binlit(cx, sp, crypted);
let key_expr = construct_binlit(cx, sp, key);
let constructor_path = vec![
token::intern("obfustring").ident(),
token::intern("construct").ident()
];
cx.expr_call_global(sp, constructor_path,
vec![crypted_expr, key_expr])
}
fn wrap_in_unsafe_block(cx: &mut ExtCtxt, sp: Span, expr: P<Expr>) -> P<Expr> {
cx.expr_block(P(ast::Block {
view_items: vec![],
stmts: vec![],
expr: Some(expr),
id: ast::DUMMY_NODE_ID,
rules: ast::UnsafeBlock(ast::CompilerGenerated),
span: sp,
}))
}
fn expand_obf(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
-> Box<MacResult + 'static> {
let text = match args {
[TtToken(_, token::Literal(token::Lit::Str_(n), _))] => n,
_ => {
cx.span_err(sp, "argument should be a string literal");
return DummyResult::any(sp);
}
};
let text = str_lit(text.as_str());
let (crypted, key) = crypt(text.as_slice());
let call_expr = construct_call(cx, sp, crypted, key);
MacExpr::new(wrap_in_unsafe_block(cx, sp, call_expr))
}
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_macro("obf", expand_obf);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment