labyrinth_macros/
lib.rs

1//! `labyrinth_macros` crate provides procedural macros for compile-time obfuscation. NOT MEANT TO BE USED STANDALONE.
2//!
3//! This crate includes macros like `encrypt_string` and `flow_stmt` which are used
4//! to enhance the security of Rust code by obfuscating strings and control flows.
5use proc_macro::TokenStream;
6use quote::quote;
7use rand::seq::SliceRandom;
8use rand::Rng;
9use std::env;
10use syn::*;
11
12/// A procedural macro that adds a compile-time randomly generated loop and variables.
13///
14/// # Note
15/// The unsafe operation is meant to help the dummy loop survive compiler optimizations. only writes to dummy variable
16///
17#[proc_macro]
18pub fn flow_stmt(_: TokenStream) -> TokenStream {
19    let mut rng = rand::thread_rng();
20
21    let initial_value = rng.gen_range(1..=10);
22    let increment_value = rng.gen_range(1..=4);
23    let upper_bound = rng.gen_range(50..=100);
24    let add_extra_dummy_variable = rng.gen_bool(0.5);
25
26    let mut statements = vec![
27        quote! { let mut _dummy_counter = std::hint::black_box(#initial_value as i32); },
28        quote! { let _dummy_increment = std::hint::black_box(#increment_value as i32); },
29        quote! { let _dummy_upper_bound = std::hint::black_box(#upper_bound as i32); },
30    ];
31
32    //add random dummy variable occasionally
33    if add_extra_dummy_variable {
34        let extra_dummy_value = rng.gen_range(1..=10);
35        statements.push(
36            quote! { let _extra_dummy_var = std::hint::black_box(#extra_dummy_value as i32); },
37        );
38    }
39
40    //randomize the order of variable assignments
41    statements.shuffle(&mut rng);
42
43    let loop_block = quote! {
44        loop {
45            if std::hint::black_box(_dummy_counter) > std::hint::black_box(_dummy_upper_bound) {
46                break;
47            }
48            //hide what expr evaluates to to stop compiler
49            _dummy_counter = std::hint::black_box(std::hint::black_box(_dummy_counter) + std::hint::black_box(_dummy_increment));
50        }
51    };
52
53    let generated_loop = quote! {
54        {
55            let _is_dummy_145 = true;
56            #(#statements)*
57            #loop_block
58        }
59    };
60
61    TokenStream::from(generated_loop)
62}
63/// A procedural macro that encrypts a string literal at compile time.
64///
65/// # Parameters
66/// - `input`: The string literal to be encrypted.
67///
68#[proc_macro]
69pub fn encrypt_string(input: TokenStream) -> TokenStream {
70    let input = parse_macro_input!(input as LitStr);
71    let string = input.value();
72
73    //set key to seeded env key or default
74    let key = env::var("CRYPTIFY_KEY").unwrap_or_else(|_| "xnasff3wcedj".to_string());
75
76    let encrypted_string = xor_cipher(&string, &key);
77
78    let output = quote! {
79        cryptify::decrypt_string(#encrypted_string)
80    };
81
82    TokenStream::from(output)
83}
84
85fn xor_cipher(input: &str, key: &str) -> String {
86    input
87        .chars()
88        .zip(key.chars().cycle())
89        .map(|(input_char, key_char)| ((input_char as u8) ^ (key_char as u8)) as char)
90        .collect()
91}
92
93//for self-contained tests
94#[allow(dead_code)]
95fn decrypt_string(encrypted: &str) -> String {
96    let key = std::env::var("CRYPTIFY_KEY").unwrap_or_else(|_| "xnasff3wcedj".to_string());
97    encrypted
98        .chars()
99        .zip(key.chars().cycle())
100        .map(|(encrypted_char, key_char)| ((encrypted_char as u8) ^ (key_char as u8)) as char)
101        .collect()
102}
103
104//unit tests testing decryption logic
105#[cfg(test)]
106mod tests {
107    use super::*;
108
109    #[test]
110    fn test_xor_cipher_and_decrypt() {
111        std::env::remove_var("CRYPTIFY_KEY");
112        let key = "xnasff3wcedj";
113        let test_strings = ["Hello", "World", "1234", "!@#$%^&*()"];
114
115        for &original in &test_strings {
116            let encrypted = xor_cipher(original, &key);
117            let decrypted = decrypt_string(&encrypted);
118            assert_eq!(original, decrypted, "Failed for string: {}", original);
119        }
120    }
121    #[test]
122    fn test_xor_cipher_and_decrypt_customkey() {
123        //set key
124        std::env::set_var("CRYPTIFY_KEY", "testkey");
125        //test loc from encrypt_string meant to extract key
126        let key = env::var("CRYPTIFY_KEY").unwrap_or_else(|_| "xnasff3wcedj".to_string());
127        assert_eq!(key, "testkey");
128
129        let test_strings = ["Hello", "World", "1234", "!@#$%^&*()"];
130        for &original in &test_strings {
131            let encrypted = xor_cipher(original, &key);
132            let decrypted = decrypt_string(&encrypted);
133            assert_eq!(original, decrypted, "Failed for string: {}", original);
134        }
135    }
136}