crypt_ro/
lib.rs

1//! A cryptographic library providing matrix-based encryption and decryption.
2//!
3//! This library implements a custom encryption scheme using:
4//! - Matrix transformations with configurable size
5//! - Key-derived shuffling operations
6//! - Random padding and mixing operations
7//! - URL-safe base64 encoding for text operations
8//!
9//! # Features
10//! - Configurable matrix size for transformation blocks
11//! - Both raw byte and text-friendly operations
12//! - Key-based encryption/decryption
13//! - Randomized padding for better security
14//!
15//! # Examples
16//!
17//! Basic usage:
18//!
19//! ```
20//! use crypt_ro::Cryptor;
21//!
22//! let cryptor = Cryptor::new();
23//! let secret = "my secret message";
24//! let key = "strong password";
25//!
26//! // Encrypt and decrypt text
27//! let encrypted = cryptor.encrypt_text(secret, key).unwrap();
28//! let decrypted = cryptor.decrypt_text(&encrypted, key).unwrap();
29//!
30//! assert_eq!(decrypted, secret);
31//!
32//! // Using custom matrix size
33//! let mut cryptor = Cryptor::new();
34//! cryptor.set_matrix(64);  // Use larger blocks
35//! let encrypted = cryptor.encrypt_text(secret, key).unwrap();
36//! let decrypted = cryptor.decrypt_text(&encrypted, key).unwrap();
37//!
38//! assert_eq!(decrypted, secret);
39//! ```
40//!
41//! Working with raw bytes:
42//!
43//! ```
44//! use crypt_ro::Cryptor;
45//!
46//! let cryptor = Cryptor::new();
47//! let data = b"binary data \x01\x02\x03";
48//! let key = "encryption key";
49//!
50//! let encrypted = cryptor.encrypt(std::str::from_utf8(data).unwrap(), key).unwrap();
51//! let decrypted = cryptor.decrypt(&encrypted, key).unwrap();
52//!
53//! assert_eq!(decrypted.as_bytes(), data);
54//! ```
55
56mod util;
57
58use base64::{engine::general_purpose::URL_SAFE, Engine as _};
59use std::error::Error;
60use crate::util::{generate_password, get_random_bytes, mix, shuffle, unmix, unshuffle};
61
62/// A cryptographic utility for encrypting and decrypting text using a matrix-based transformation.
63///
64/// The `Cryptor` uses a combination of shuffling, mixing, and matrix operations to obscure the
65/// original text. It supports configurable matrix sizes for the transformation process.
66///
67/// # Examples
68///
69/// ```
70/// use crypt_ro::Cryptor;
71///
72/// let cryptor = Cryptor::new();
73/// let encrypted = cryptor.encrypt_text("secret message", "password").unwrap();
74/// let decrypted = cryptor.decrypt_text(&encrypted, "password").unwrap();
75/// assert_eq!(decrypted, "secret message");
76/// ```
77pub struct Cryptor {
78    matrix: usize,
79}
80
81impl Cryptor {
82    /// Creates a new `Cryptor` instance with default matrix size (32).
83    pub fn new() -> Self {
84        Self { matrix: 32 }
85    }
86
87    /// Encrypts raw bytes using the provided key.
88    ///
89    /// # Arguments
90    /// * `text` - The plaintext to encrypt
91    /// * `key` - The encryption key
92    ///
93    /// # Returns
94    /// A `Result` containing the encrypted bytes or an error if encryption fails.
95    ///
96    /// # Example
97    /// ```
98    /// use crypt_ro::Cryptor;
99    ///
100    /// let cryptor = Cryptor::new();
101    /// let encrypted = cryptor.encrypt("secret data", "key123").unwrap();
102    /// assert!(!encrypted.is_empty());
103    /// ```
104    pub fn encrypt(&self, text: &str, key: &str) -> Result<Vec<u8>, Box<dyn Error>> {
105        let matrix_size=self.matrix;
106        let key_bytes = generate_password(matrix_size,key.as_bytes());
107
108        let random_prefix = get_random_bytes(6);
109
110        let mut padded_text = Vec::with_capacity(random_prefix.len() + text.len());
111        padded_text.extend_from_slice(&random_prefix);
112        padded_text.extend_from_slice(text.as_bytes());
113
114        let pad_len = (matrix_size - (padded_text.len() % matrix_size)) % matrix_size;
115        padded_text.resize(padded_text.len() + pad_len, 0);
116
117        let seed_sum: u64 = key_bytes.iter().map(|&b| b as u64).sum();
118        shuffle(&mut padded_text,seed_sum,5);
119
120        let mut matrix = padded_text.chunks_exact_mut(matrix_size).collect::<Vec<_>>();
121        let matrix_len=matrix.len();
122
123        for i in 0..matrix_len {
124            let seed = match matrix.get(i+1) {
125                None => {
126                    key_bytes[0] as u64}
127                Some(a) => {
128                        a[0] as u64
129                }
130            };
131            shuffle(&mut matrix[i], seed,2);
132        }
133
134        mix(matrix_size,&mut padded_text, &key_bytes);
135
136        Ok(padded_text)
137    }
138
139
140    /// Encrypts raw bytes using the provided key.
141    ///
142    /// # Arguments
143    /// * `text` - The plaintext to encrypt
144    /// * `key` - The encryption key
145    ///
146    /// # Returns
147    /// A `Result` URL-safe base64 string without padding or an error if encryption fails.
148    ///
149    /// # Example
150    /// ```
151    /// use crypt_ro::Cryptor;
152    ///
153    /// let cryptor = Cryptor::new();
154    /// let encrypted = cryptor.encrypt_text("secret message", "password").unwrap();
155    /// assert!(!encrypted.contains('/'));  // URL-safe
156    pub fn encrypt_text(&self, text: &str, key: &str) -> Result<String, Box<dyn Error>> {
157        Ok(URL_SAFE.encode(self.encrypt(text, key)?).trim_end_matches('=').to_string())
158    }
159
160    /// Decrypts bytes using the provided key.
161    ///
162    /// # Arguments
163    /// * `encoded` - The encrypted bytes to decrypt
164    /// * `key` - The decryption key
165    ///
166    /// # Returns
167    /// A `Result` containing the decrypted string or an error if decryption fails.
168    ///
169    /// # Example
170    /// ```
171    /// use crypt_ro::Cryptor;
172    ///
173    /// let cryptor = Cryptor::new();
174    /// let encrypted = cryptor.encrypt("data", "key").unwrap();
175    /// let decrypted = cryptor.decrypt(&encrypted, "key").unwrap();
176    /// assert_eq!(decrypted, "data");
177    /// ```
178    pub fn decrypt(&self, encoded: &Vec<u8>, key: &str) -> Result<String, Box<dyn Error>> {
179        let mut decoded = encoded.clone();
180        let matrix_size=self.matrix;
181        if decoded.len() % matrix_size != 0 {
182            return Err("Invalid Token Matrix Length".into());
183        }
184
185        let key_bytes = generate_password(matrix_size,key.as_bytes());
186        unmix(matrix_size,&mut decoded, &key_bytes);
187        let mut matrix = decoded.chunks_exact_mut(matrix_size).collect::<Vec<_>>();
188        let matrix_len=matrix.len();
189        for i in (0..matrix_len).rev() {
190            let seed = match matrix.get(i + 1) {
191                None => {key_bytes[0] as u64}
192                Some(a) => {a[0] as u64}
193            };
194            unshuffle(&mut matrix[i], seed,2);
195        }
196
197
198        let seed_sum: u64 = key_bytes.iter().map(|&b| b as u64).sum();
199        unshuffle(&mut decoded, seed_sum,5);
200
201        if decoded.len() < matrix_size {
202            return Err("Invalid Token Matrix Length".into());
203        }
204        let result_bytes = &decoded[6..];
205        let result = String::from_utf8(result_bytes.to_vec())?
206            .trim_end_matches('\0')
207            .to_string();
208
209        Ok(result)
210    }
211
212    /// Decrypts a URL-safe base64 encoded string using the provided key.
213    ///
214    /// # Arguments
215    /// * `encoded` - A URL-safe base64 encoded string to decrypt
216    /// * `key` - The decryption key
217    ///
218    /// # Returns
219    /// A `Result` containing the decrypted string or an error if decryption fails.
220    ///
221    /// # Example
222    /// ```
223    /// use crypt_ro::Cryptor;
224    ///
225    /// let cryptor = Cryptor::new();
226    /// let encrypted = cryptor.encrypt_text("message", "pass").unwrap();
227    /// let decrypted = cryptor.decrypt_text(&encrypted, "pass").unwrap();
228    /// assert_eq!(decrypted, "message");
229    /// ```
230    pub fn decrypt_text(&self, encoded: &str, key: &str) -> Result<String, Box<dyn Error>> {
231        let mut input = encoded.to_string();
232        let padding = input.len() % 4;
233        if padding != 0 {
234            input.push_str(&"=".repeat(4 - padding));
235        }
236
237        let data = URL_SAFE.decode(&input)?;
238
239        Ok(self.decrypt(&data, &key)?)
240    }
241
242    /// Sets the matrix size used for cryptographic operations.
243    ///
244    /// The matrix size determines how data is chunked and processed during encryption/decryption.
245    /// Must be a positive non-zero value.
246    ///
247    /// # Example
248    /// ```
249    /// use crypt_ro::Cryptor;
250    ///
251    /// let mut cryptor = Cryptor::new();
252    /// cryptor.set_matrix(64);  // Use larger blocks
253    /// ```
254    pub fn set_matrix(&mut self, size: usize) {
255        if size>0{
256            self.matrix = size;
257        }
258    }
259}