Skip to main content

xor_cryptor/
lib.rs

1//! Cipher and decipher using algorithm based on XOR bitwise operation
2//!
3//! # Usage
4//!
5//! ### For V2:
6//! ```
7//! use xor_cryptor::XORCryptor;
8//!
9//! fn main() {
10//!    let sample_text = String::from("Hello World !");
11//!    let key = String::from("secret_key");
12//!    let buffer = sample_text.as_bytes().to_vec();
13//!
14//!    let encrypted_buffer = match XORCryptor::encrypt_v2(key.as_bytes(), buffer) {
15//!        Ok(enc) => enc,
16//!        Err(e) => {
17//!            println!("Error: {}", e);
18//!            return;
19//!        }
20//!    };
21//!
22//!    let encrypted_string = String::from_utf8_lossy(&encrypted_buffer);
23//!    println!("Encrypted: {}\n", encrypted_string);
24//!
25//!    // Never convert encrypted buffer into string
26//!    // This encrypted string contains formatted non-utf8 characters
27//!    // Do not use this string as vector to decrypt
28//!    let decrypted_buffer =
29//!        match XORCryptor::decrypt_v2(key.as_bytes(), encrypted_string.as_bytes().to_vec()) {
30//!            Ok(d) => d,
31//!            Err(e) => {
32//!                println!("Error: {}", e);
33//!                return;
34//!            }
35//!        };
36//!    println!(
37//!        "Decrypted from string : {:?}",
38//!        String::from_utf8_lossy(&decrypted_buffer)
39//!    );
40//!
41//!    let decrypted_buffer = match XORCryptor::decrypt_v2(key.as_bytes(), encrypted_buffer) {
42//!        Ok(d) => d,
43//!        Err(e) => {
44//!            println!("Error: {}", e);
45//!            return;
46//!        }
47//!    };
48//!    println!(
49//!        "Decrypted from vec    : {:?}",
50//!        String::from_utf8_lossy(&decrypted_buffer)
51//!    );
52//! }
53//! ```
54//!
55//! ## Output
56//! ```shell
57//! $ cargo run --release --bin main
58//!    Compiling xor_cryptor v1.2.3 (/Users/shank/Developer/Projects/XORCryptor-Rust)
59//!     Finished `release` profile [optimized] target(s) in 0.42s
60//!      Running `target/release/main`
61//! Encrypted: _h�OUrF�bq�h��=������
62//!
63//! Decrypted from string : "\u{16}Y�\u{7ac}��|�YCfOe\u{14}\u{11}�yJ �/���\u{6}h\u{15}.sY\u{17}\u{13}�k�9�c��\0�\0�\0�\0\0"
64//!
65//! Decrypted from vec    : "Hello World !"
66//! ```
67//!
68//! ### For V1:
69//! ```
70//! use xor_cryptor::XORCryptor;
71//!
72//! fn main() {
73//!     let sample_text = String::from("Hello World !");
74//!     let key = String::from("secret_key");
75//!     let buffer = sample_text.as_bytes().to_vec();
76//!
77//!     let res = XORCryptor::new(&key);
78//!     if res.is_err() {
79//!         return;
80//!     }
81//!     let xrc = res.unwrap();
82//!
83//!     let encrypted_buffer = xrc.encrypt_vec(buffer);
84//!     let encrypted_string = String::from_utf8_lossy(&encrypted_buffer);
85//!     println!("Encrypted: {}\n", encrypted_string);
86//!
87//!     // This encrypted string contains formatted non-utf8 characters
88//!     // Do not use this string as vector to decrypt
89//!     let decrypted_buffer = xrc.decrypt_vec(encrypted_string.as_bytes().to_vec());
90//!     println!(
91//!         "Decrypted from string : {:?}",
92//!         String::from_utf8_lossy(&decrypted_buffer)
93//!     );
94//!
95//!     let decrypted_buffer = xrc.decrypt_vec(encrypted_buffer);
96//!     println!(
97//!         "Decrypted from vec    : {:?}",
98//!         String::from_utf8_lossy(&decrypted_buffer)
99//!     );
100//! }
101//! ```
102//!
103//! ## Output
104//! ```shell
105//! $ cargo run
106//!   Compiling xor_cryptor v1.0.0 (XYZ)
107//!    Finished dev [unoptimized + debuginfo] target(s) in 0.21s
108//!     Running `target/debug/xor_cryptor.exe`
109//!
110//! Encrypted: W"♣'"�jMLQ�-
111//!
112//! Decrypted from string: "Hell:4u��D6S\u{c}\u{1e}��K"
113//! Decrypted from vec   : "Hello World !"
114//! ```
115
116use std::{any::TypeId, marker::PhantomData, mem};
117
118use err::XRCResult;
119use rayon::iter::{IntoParallelIterator, ParallelIterator};
120
121mod cipher;
122mod test;
123mod v2;
124
125pub mod err;
126
127pub trait XrcVersion {}
128pub struct V1;
129impl XrcVersion for V1 {}
130pub struct V2;
131impl XrcVersion for V2 {}
132
133#[cfg(target_pointer_width = "64")]
134pub struct XORCryptor<T> {
135    cipher: cipher::Cipher,
136    e_table: Vec<u16>,
137    d_table: Vec<u16>,
138    raw_seed: usize,
139    _marker: PhantomData<T>,
140}
141
142#[cfg(target_pointer_width = "64")]
143impl<T: XrcVersion> XORCryptor<T> {
144    fn generate_table(e_table: &mut Vec<u16>, d_table: &mut Vec<u16>) {
145        let (mut count, mut shift, mut value, mut bit_mask): (u16, u16, u16, u16);
146        let (mut mask, mut mode) = (0u16, 0u16);
147
148        for i in 0..=255 as u16 {
149            (count, shift, value) = (4, 0, i);
150            while count != 0 {
151                bit_mask = value & 3;
152                let mask_shift: u16 = (bit_mask > 1).into();
153                let mode_shift: u16 = (bit_mask == 0 || bit_mask == 3).into();
154                mask |= mask_shift << shift;
155                mode |= mode_shift << shift;
156
157                count -= 1;
158                shift += 1;
159                value >>= 2;
160            }
161            mask = (mode << 8) | mask;
162            e_table[i as usize] = mask;
163            d_table[mask as usize] = i;
164            (mask, mode) = (0, 0);
165        }
166    }
167
168    #[inline]
169    fn encrypt_byte(&self, val: usize) -> usize {
170        self.e_table[val & 0xFF] as usize
171            | (self.e_table[(val >> 0x8) & 0xFF] as usize) << 0x4
172            | (self.e_table[(val >> 0x10) & 0xFF] as usize) << 0x10
173            | (self.e_table[(val >> 0x18) & 0xFF] as usize) << 0x14
174            | (self.e_table[(val >> 0x20) & 0xFF] as usize) << 0x20
175            | (self.e_table[(val >> 0x28) & 0xFF] as usize) << 0x24
176            | (self.e_table[(val >> 0x30) & 0xFF] as usize) << 0x30
177            | (self.e_table[(val >> 0x38) & 0xFF] as usize) << 0x34
178    }
179
180    #[inline]
181    fn decrypt_byte(&self, val: usize) -> usize {
182        self.d_table[val & 0x0F0F] as usize
183            | (self.d_table[(val >> 0x4) & 0x0F0F] as usize) << 0x8
184            | (self.d_table[(val >> 0x10) & 0x0F0F] as usize) << 0x10
185            | (self.d_table[(val >> 0x14) & 0x0F0F] as usize) << 0x18
186            | (self.d_table[(val >> 0x20) & 0x0F0F] as usize) << 0x20
187            | (self.d_table[(val >> 0x24) & 0x0F0F] as usize) << 0x28
188            | (self.d_table[(val >> 0x30) & 0x0F0F] as usize) << 0x30
189            | (self.d_table[(val >> 0x34) & 0x0F0F] as usize) << 0x38
190    }
191
192    pub fn get_cipher(&self) -> &[usize] {
193        self.cipher.get_cipher()
194    }
195}
196
197#[cfg(target_pointer_width = "64")]
198impl XORCryptor<V1> {
199    /// Initialize with the key
200    pub fn new(key: &str) -> XRCResult<Self> {
201        let cipher = cipher::Cipher::from(key)?;
202        Ok(XORCryptor::init(cipher))
203    }
204
205    pub fn new_bytes(key: &[u8]) -> XRCResult<Self> {
206        let cipher = cipher::Cipher::from_bytes(key)?;
207        Ok(XORCryptor::init(cipher))
208    }
209
210    fn init(cipher: cipher::Cipher) -> Self {
211        let (mut e_table, mut d_table) = (vec![0u16; 256], vec![0u16; 0xF10]);
212        Self::generate_table(&mut e_table, &mut d_table);
213        XORCryptor {
214            cipher,
215            e_table,
216            d_table,
217            raw_seed: 0,
218            _marker: PhantomData,
219        }
220    }
221
222    fn encrypt_buffer(&self, src: &mut Vec<usize>, b_len: usize) {
223        let mut byte_count = b_len;
224        let odd = b_len % 8 != 0;
225        let length = src.len() - if odd { 1 } else { 0 };
226        let src_ptr = Ptr(src.as_mut_ptr());
227
228        byte_count -= 8 * length;
229
230        (0..length).into_par_iter().for_each(move |i| unsafe {
231            let val = *{ src_ptr }.0.add(i);
232            let mut lxi = self.encrypt_byte(val);
233
234            lxi = ((lxi & 0x00FF_00FF_00FF_00FF) << 8) ^ lxi;
235            *{ src_ptr }.0.add(i) = lxi ^ self.cipher.get_cipher_byte(i);
236        });
237
238        if odd {
239            let (val, mut shift) = (src[length], 0usize);
240            let mut lxi = 0usize;
241            while byte_count > 1 {
242                lxi |= (self.e_table[(val >> shift) & 0xFF] as usize) << shift
243                    | ((self.e_table[((val >> 8) >> shift) & 0xFF] as usize) << 4) << shift;
244                shift += 16;
245                byte_count -= 2;
246            }
247            let mut mm = self.e_table[(val >> shift) & 0xFF] as usize;
248            mm = ((mm & 0xF00) >> 8) | ((mm & 0xF) << 4);
249            mm ^= mm >> 4;
250            lxi |= mm << shift;
251            lxi = ((lxi & 0x00FF_00FF_00FF_00FF) << 8) ^ lxi;
252            src[length] = lxi ^ self.cipher.get_cipher_byte(length);
253        }
254    }
255
256    fn decrypt_buffer(&self, src: &mut Vec<usize>, b_len: usize) {
257        let mut byte_count = b_len;
258        let odd = b_len % 8 != 0;
259        let length = src.len() - if odd { 1 } else { 0 };
260        let src_ptr = Ptr(src.as_mut_ptr());
261
262        byte_count -= 8 * length;
263
264        (0..length).into_par_iter().for_each(move |i| unsafe {
265            *{ src_ptr }.0.add(i) ^= self.cipher.get_cipher_byte(i);
266            let val = *{ src_ptr }.0.add(i);
267            let xi = ((val & 0x00FF_00FF_00FF_00FF) << 8) ^ val;
268
269            *{ src_ptr }.0.add(i) = self.decrypt_byte(xi);
270        });
271
272        if odd {
273            src[length] ^= self.cipher.get_cipher_byte(length);
274            let xi = ((src[length] & 0x00FF_00FF_00FF_00FF) << 8) ^ src[length];
275            let (mut lxi, mut shift) = (0usize, 0usize);
276            while byte_count > 1 {
277                lxi |= (self.d_table[(xi >> shift) & 0x0F0F] as usize) << shift
278                    | (self.d_table[(xi >> shift >> 4) & 0x0F0F] as usize) << 8 << shift;
279                shift += 0x10;
280                byte_count -= 2;
281            }
282            let mut mm = (xi >> shift) & 0xFF;
283            mm ^= mm >> 4;
284            mm = ((mm & 0xF0) >> 4) | ((mm & 0xF) << 8);
285            lxi |= (self.d_table[mm] as usize) << shift;
286            src[length] = lxi;
287        }
288    }
289
290    /// Encrypts the vector
291    ///
292    /// IMPORTANT!
293    ///
294    /// This method is NOT suitable for production use as
295    /// it uses ECB. Hence, takes advantage of parallelism
296    /// for higher through put
297    ///
298    /// [Breaking Change]: Use [`Self::encrypt_v2`] for more secure and suitable for production use
299    #[deprecated]
300    pub fn encrypt_vec(&self, buffer: Vec<u8>) -> Vec<u8> {
301        if buffer.is_empty() {
302            return vec![];
303        }
304        let b_len = buffer.len();
305        let mut src = transmute_buffer::<u8, usize>(buffer, 0, 0, Version::V1);
306        self.encrypt_buffer(&mut src, b_len);
307        transmute_buffer(src, b_len, 0, Version::V1)
308    }
309
310    /// Decrypts the vector
311    ///
312    /// IMPORTANT!
313    ///
314    /// This method is NOT suitable for production use.
315    ///
316    /// [Breaking Change]: Use [`Self::decrypt_v2`].
317    #[deprecated]
318    pub fn decrypt_vec(&self, buffer: Vec<u8>) -> Vec<u8> {
319        if buffer.is_empty() {
320            return vec![];
321        }
322        let b_len = buffer.len();
323        let mut src = transmute_buffer::<u8, usize>(buffer, 0, 0, Version::V1);
324        self.decrypt_buffer(&mut src, b_len);
325        transmute_buffer(src, b_len, 0, Version::V1)
326    }
327}
328
329#[derive(Copy, Clone)]
330struct Ptr<T>(*mut T);
331unsafe impl<T> Send for Ptr<T> {}
332unsafe impl<T> Sync for Ptr<T> {}
333
334enum Version {
335    V1,
336    V2,
337}
338
339/// Transmutes buffer from Vec<u8> to Vec<usize> and vice-versa
340fn transmute_buffer<T, R>(mut buffer: Vec<T>, b_len: usize, default: T, version: Version) -> Vec<R>
341where
342    T: Sized + Clone + 'static,
343    R: Sized + 'static,
344{
345    let (t, r) = (TypeId::of::<T>(), TypeId::of::<R>());
346    let (t8, t_usize) = (TypeId::of::<u8>(), TypeId::of::<usize>());
347
348    if (t != t8 || r != t_usize) && (t != t_usize || r != t8) {
349        return vec![];
350    }
351
352    let from_u8_usize = t == t8 && r == t_usize;
353    let len = buffer.len();
354    let (upper, rem) = (len + 8, len % 8);
355    let rem_a = upper % 8;
356
357    let length = if from_u8_usize {
358        let rz: usize = (rem == 0).into();
359        ((len * rz) + (upper * (1 - rz))) / 8
360    } else {
361        len * 8
362    };
363
364    if from_u8_usize {
365        let addition = if rem == 0 { 0 } else { upper - rem_a - len };
366        buffer.resize(
367            buffer.len()
368                + addition
369                + match version {
370                    Version::V1 => 0,
371                    Version::V2 => 2,
372                },
373            default,
374        );
375    }
376
377    let mut data: Vec<R>;
378    // T and R are asserted to be either u8 or usize.
379    // The length and capacity are calculated and padded above
380    // based on conversion of types.
381    // Creating vector using interpreted ptr and desired length
382    // will not crash.
383    unsafe {
384        let mutptr = buffer.as_ptr() as *mut R;
385        mem::forget(buffer);
386        data = Vec::from_raw_parts(mutptr, length, length)
387    }
388    if !from_u8_usize && b_len != 0 {
389        // Remove additional padding
390        data.truncate(b_len);
391    }
392    data
393}