labyrinth_macros/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//! `labyrinth_macros` crate provides procedural macros for compile-time obfuscation. NOT MEANT TO BE USED STANDALONE.
//!
//! This crate includes macros like `encrypt_string` and `flow_stmt` which are used
//! to enhance the security of Rust code by obfuscating strings and control flows.
use proc_macro::TokenStream;
use quote::quote;
use syn::*;
use std::env;
use rand::Rng;
use rand::seq::SliceRandom;

/// A procedural macro that adds a compile-time randomly generated loop and variables.
///
/// # Note
/// The unsafe operation is meant to help the dummy loop survive compiler optimizations. only writes to dummy variable
///
#[proc_macro]
pub fn flow_stmt(_: TokenStream) -> TokenStream {
    let mut rng = rand::thread_rng();

    let initial_value = rng.gen_range(1..=10);
    let increment_value = rng.gen_range(1..=4);
    let add_extra_dummy_variable = rng.gen_bool(0.5);

    let mut statements = vec![
        quote! { let mut _dummy_counter = #initial_value; },
        quote! { let _dummy_increment = #increment_value; },
        quote! { let _dummy_upper_bound = 100; }
    ];

    //add random dummy variable occasionally
    if add_extra_dummy_variable {
        let extra_dummy_value = rng.gen_range(1..=10);
        statements.push(quote! { let _extra_dummy_var = #extra_dummy_value; });
    }

    //randomize the order of variable assignments
    statements.shuffle(&mut rng);

    let loop_block =
        quote! {
        loop {
            if _dummy_counter > _dummy_upper_bound {
                break;
            }
            //prevent compiler optimizations
            unsafe {
                std::ptr::write_volatile(&mut _dummy_counter, _dummy_counter + _dummy_increment);
            }
        }
    };

    let generated_loop =
        quote! {
        {
            let _is_dummy_145 = true;
            #(#statements)*
            #loop_block
        }
    };

    TokenStream::from(generated_loop)
}
/// A procedural macro that encrypts a string literal at compile time.
///
/// # Parameters
/// - `input`: The string literal to be encrypted.
///
#[proc_macro]
pub fn encrypt_string(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as LitStr);
    let string = input.value();

    //set key to seeded env key or default
    let key = env::var("CRYPTIFY_KEY").unwrap_or_else(|_| "xnasff3wcedj".to_string());

    let encrypted_string = xor_cipher(&string, &key);

    let output = quote! {
        cryptify::decrypt_string(#encrypted_string).as_ref()
    };

    TokenStream::from(output)
}

fn xor_cipher(input: &str, key: &str) -> String {
    input
        .chars()
        .zip(key.chars().cycle())
        .map(|(input_char, key_char)| { ((input_char as u8) ^ (key_char as u8)) as char })
        .collect()
}

//for self-contained tests
#[allow(dead_code)]
fn decrypt_string(encrypted: &str) -> String {
    let key = std::env::var("CRYPTIFY_KEY").unwrap_or_else(|_| "xnasff3wcedj".to_string());
    encrypted
        .chars()
        .zip(key.chars().cycle())
        .map(|(encrypted_char, key_char)| ((encrypted_char as u8) ^ (key_char as u8)) as char)
        .collect()
}

//unit tests testing decryption logic
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_xor_cipher_and_decrypt() {
        let key = "xnasff3wcedj";
        let test_strings = ["Hello", "World", "1234", "!@#$%^&*()"];

        for &original in &test_strings {
            let encrypted = xor_cipher(original, &key);
            let decrypted = decrypt_string(&encrypted);
            assert_eq!(original, decrypted, "Failed for string: {}", original);
        }
    }
    #[test]
    fn test_xor_cipher_and_decrypt_customkey() {
        //set key
        std::env::set_var("CRYPTIFY_KEY", "testkey");
        //test loc from encrypt_string meant to extract key
        let key = env::var("CRYPTIFY_KEY").unwrap_or_else(|_| "xnasff3wcedj".to_string());
        assert_eq!(key, "testkey");

        let test_strings = ["Hello", "World", "1234", "!@#$%^&*()"];
        for &original in &test_strings {
            let encrypted = xor_cipher(original, &key);
            let decrypted = decrypt_string(&encrypted);
            assert_eq!(original, decrypted, "Failed for string: {}", original);
        }
    }
}