Skip to main content

rustcrypt_ct_macros/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, LitByteStr, LitStr};
4
5#[proc_macro]
6pub fn obf_lit(input: TokenStream) -> TokenStream {
7    let lit = parse_macro_input!(input as LitStr);
8    let bytes = lit.value().into_bytes();
9
10    let mut keystream = Vec::with_capacity(bytes.len());
11    let mut s: u64 = 0xA076_1D64 ^ (bytes.len() as u64).wrapping_mul(0x9E37_79B9);
12    for _ in 0..bytes.len() {
13        s ^= s << 13;
14        s ^= s >> 7;
15        s ^= s << 17;
16        keystream.push(((s ^ (s >> 11)) & 0xFF) as u8);
17    }
18
19    let obf: Vec<u8> = bytes
20        .iter()
21        .enumerate()
22        .map(|(i, b)| b ^ keystream[i])
23        .collect();
24
25    let n = obf.len();
26    let obf_tokens = quote! { [#(#obf),*] };
27    let key_tokens = quote! { [#(#keystream),*] };
28
29    let expanded = quote! {{
30        const __OBF: [u8; #n] = #obf_tokens;
31        const __KEY: [u8; #n] = #key_tokens;
32        let mut __buf = vec![0u8; #n];
33        let mut __i = 0usize;
34        while __i < #n { __buf[__i] = __OBF[__i] ^ __KEY[__i]; __i += 1; }
35        String::from_utf8(__buf).expect("obf_lit produced invalid UTF-8")
36    }};
37
38    TokenStream::from(expanded)
39}
40
41/// Obfuscate a byte string literal at compile time and produce a runtime `Vec<u8>`.
42#[proc_macro]
43pub fn obf_lit_bytes(input: TokenStream) -> TokenStream {
44    let lit = parse_macro_input!(input as LitByteStr);
45    let bytes = lit.value();
46
47    let mut keystream = Vec::with_capacity(bytes.len());
48    let mut s: u64 = 0xA076_1D64 ^ (bytes.len() as u64).wrapping_mul(0x9E37_79B9);
49    for _ in 0..bytes.len() {
50        s ^= s << 13;
51        s ^= s >> 7;
52        s ^= s << 17;
53        keystream.push(((s ^ (s >> 11)) & 0xFF) as u8);
54    }
55
56    let obf: Vec<u8> = bytes
57        .iter()
58        .enumerate()
59        .map(|(i, b)| b ^ keystream[i])
60        .collect();
61
62    let n = obf.len();
63    let obf_tokens = quote! { [#(#obf),*] };
64    let key_tokens = quote! { [#(#keystream),*] };
65
66    let expanded = quote! {{
67        const __OBF: [u8; #n] = #obf_tokens;
68        const __KEY: [u8; #n] = #key_tokens;
69        let mut __buf = vec![0u8; #n];
70        let mut __i = 0usize;
71        while __i < #n { __buf[__i] = __OBF[__i] ^ __KEY[__i]; __i += 1; }
72        __buf
73    }};
74
75    TokenStream::from(expanded)
76}
77
78#[proc_macro]
79pub fn obf_lit_cstr(input: TokenStream) -> TokenStream {
80    let lit = parse_macro_input!(input as LitStr);
81    let mut bytes = lit.value().into_bytes();
82    bytes.push(0);
83    let mut keystream = Vec::with_capacity(bytes.len());
84    let mut s: u64 = 0xA076_1D64 ^ (bytes.len() as u64).wrapping_mul(0x9E37_79B9);
85    for _ in 0..bytes.len() { s ^= s << 13; s ^= s >> 7; s ^= s << 17; keystream.push(((s ^ (s >> 11)) & 0xFF) as u8); }
86    let obf: Vec<u8> = bytes.iter().enumerate().map(|(i, b)| b ^ keystream[i]).collect();
87    let n = obf.len();
88    let obf_tokens = quote! { [#(#obf),*] };
89    let key_tokens = quote! { [#(#keystream),*] };
90    let expanded = quote! {{
91        const __OBF: [u8; #n] = #obf_tokens;
92        const __KEY: [u8; #n] = #key_tokens;
93        let mut __buf = vec![0u8; #n];
94        let mut __i = 0usize;
95        while __i < #n { __buf[__i] = __OBF[__i] ^ __KEY[__i]; __i += 1; }
96        __buf
97    }};
98    TokenStream::from(expanded)
99}
100
101#[proc_macro]
102pub fn obf_lit_array(input: TokenStream) -> TokenStream {
103    let lit = parse_macro_input!(input as LitByteStr);
104    let bytes = lit.value();
105    let mut keystream = Vec::with_capacity(bytes.len());
106    let mut s: u64 = 0xA076_1D64 ^ (bytes.len() as u64).wrapping_mul(0x9E37_79B9);
107    for _ in 0..bytes.len() { s ^= s << 13; s ^= s >> 7; s ^= s << 17; keystream.push(((s ^ (s >> 11)) & 0xFF) as u8); }
108    let obf: Vec<u8> = bytes.iter().enumerate().map(|(i, b)| b ^ keystream[i]).collect();
109    let n = obf.len();
110    let obf_tokens = quote! { [#(#obf),*] };
111    let key_tokens = quote! { [#(#keystream),*] };
112    let expanded = quote! {{
113        const __OBF: [u8; #n] = #obf_tokens;
114        const __KEY: [u8; #n] = #key_tokens;
115        (__OBF, __KEY)
116    }};
117    TokenStream::from(expanded)
118}