xor_cryptor 2.0.4

A encryption/decryption library using bitwise xor
Documentation
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha20Rng;

use crate::err::{XRCError, XRCResult};

#[cfg(target_pointer_width = "64")]
pub struct Cipher {
    cipher: Vec<usize>,
}

#[cfg(target_pointer_width = "64")]
impl Cipher {
    pub fn from(key: &str) -> XRCResult<Self> {
        Cipher::init(key.as_bytes().to_vec(), None)
    }

    pub fn from_bytes(key: &[u8]) -> XRCResult<Self> {
        Cipher::init(key.to_vec(), None)
    }

    pub fn from_seed(key: &[u8], seed: u64) -> XRCResult<Self> {
        Cipher::init(key.to_vec(), Some(seed))
    }

    fn init(key: Vec<u8>, seed: Option<u64>) -> XRCResult<Self> {
        if key.len() < 6 {
            return Err(XRCError::InvalidKeyLength);
        }
        let mut cipher = match seed {
            Some(seed) => Cipher::x64_cipher_seed(key, seed),
            None => Cipher::x64_cipher(key),
        };
        for i in 0..cipher.len() {
            cipher[i] = Cipher::generate_mask(cipher[i]);
        }
        Ok(Cipher { cipher })
    }

    pub fn empty() -> Self {
        Cipher { cipher: vec![] }
    }

    #[inline]
    pub fn get_cipher_byte(&self, i: usize) -> usize {
        self.cipher[i % self.cipher.len()]
    }

    pub fn get_cipher(&self) -> &[usize] {
        &self.cipher
    }

    fn generate_mask(v: usize) -> usize {
        let (mask, mut vt, mut shift) = (0x0101_0101_0101_0101usize, v, 8usize);
        let (mut bv, mut bz) = (0usize, 0x0808_0808_0808_0808usize);
        let mut bm: usize;
        while shift != 0 {
            bm = mask & vt;
            bv += bm;
            bz -= bm;
            vt >>= 1;
            shift -= 1;
        }
        ((bz << 4) | bv) ^ ((bv << 4) | bz) ^ v
    }

    fn x64_cipher(arr: Vec<u8>) -> Vec<usize> {
        let (rep, mut idx) = (
            {
                let (mut x, mut y) = (arr.len(), 8);
                while y != 0 {
                    let temp = y;
                    y = x % y;
                    x = temp;
                }
                (arr.len() / x) * 8
            },
            0usize,
        );
        let mut data = vec![0u8; rep];
        while idx != rep {
            data[idx] = arr[idx % arr.len()];
            idx += 1;
        }
        unsafe {
            let (_, cipher_64, _) = data.align_to::<usize>();
            cipher_64.to_vec()
        }
    }

    fn x64_cipher_seed(arr: Vec<u8>, seed: u64) -> Vec<usize> {
        let rep = {
            let (mut x, mut y) = (arr.len(), 8);
            while y != 0 {
                let temp = y;
                y = x % y;
                x = temp;
            }
            (arr.len() / x) * 8
        };

        let mut rng = ChaCha20Rng::seed_from_u64(seed);
        let mut data = vec![0u8; rep];
        for i in 0..rep {
            data[i] = arr[rng.gen_range(0..arr.len())];
        }
        unsafe {
            let (_, cipher_64, _) = data.align_to::<usize>();
            cipher_64.to_vec()
        }
    }
}