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(data, key).unwrap();
51//! let decrypted = cryptor.decrypt(&encrypted, key).unwrap();
52//!
53//! assert_eq!(decrypted.as_bytes(), data);
54//! ```
55
56mod util;
57mod rand;
58
59use base64::{engine::general_purpose::URL_SAFE, Engine as _};
60use std::error::Error;
61use std::iter::repeat;
62use crate::rand::SimpleRng;
63use crate::util::{generate_password, mix, shuffle, unmix, unshuffle};
64
65/// A cryptographic utility for encrypting and decrypting text using a matrix-based transformation.
66///
67/// The `Cryptor` uses a combination of shuffling, mixing, and matrix operations to obscure the
68/// original text. It supports configurable matrix sizes for the transformation process.
69///
70/// # Examples
71///
72/// ```
73/// use crypt_ro::Cryptor;
74///
75/// let cryptor = Cryptor::new();
76/// let encrypted = cryptor.encrypt_text("secret message", "password").unwrap();
77/// let decrypted = cryptor.decrypt_text(&encrypted, "password").unwrap();
78/// assert_eq!(decrypted, "secret message");
79/// ```
80pub struct Cryptor {
81 matrix: usize,
82}
83const RANDOM_LEN: usize = 3;
84impl Cryptor {
85 /// Creates a new `Cryptor` instance with default matrix size (32).
86 pub fn new() -> Self {
87 Self { matrix: 32 }
88 }
89
90 /// Encrypts raw bytes using the provided key.
91 ///
92 /// # Arguments
93 /// * `data` - The bytes to encrypt
94 /// * `key` - The encryption key
95 ///
96 /// # Returns
97 /// A `Result` containing the encrypted bytes or an error if encryption fails.
98 ///
99 /// # Example
100 /// ```
101 /// use crypt_ro::Cryptor;
102 ///
103 /// let cryptor = Cryptor::new();
104 /// let encrypted = cryptor.encrypt(b"secret data", "key123").unwrap();
105 /// assert!(!encrypted.is_empty());
106 /// ```
107 pub fn encrypt(&self, data: &[u8], key: &str) -> Result<Vec<u8>, Box<dyn Error>> {
108 let matrix_size=self.matrix;
109 let pad = (matrix_size - ((10 + data.len()) % matrix_size)) % matrix_size;
110 let key_bytes = generate_password(matrix_size,key.as_bytes());
111 let data_len = data.len();
112 if data_len>u32::MAX as usize {
113 return Err("Data too Big".into());
114 }
115 let data_size = (data_len as u32).to_be_bytes();
116 let random_prefix = SimpleRng::new_with_time_seed().get_random_bytes(6);
117 let seed_random = random_prefix.iter().map(|&b| b as u16).sum::<u16>() as u64;
118 let mut padded_text = Vec::with_capacity(10 + data.len()+pad);
119 padded_text.extend_from_slice(&data_size);
120 padded_text.extend_from_slice(&random_prefix);
121 padded_text.extend_from_slice(data);
122 padded_text.extend(repeat(1).take(pad));
123 let seed_sum: u64 = key_bytes.iter().map(|&b| b as u64).sum();
124 shuffle(&mut padded_text,seed_sum.wrapping_add(seed_random),5);
125
126 let mut matrix = padded_text.chunks_exact_mut(matrix_size).collect::<Vec<_>>();
127 let matrix_len=matrix.len();
128 if matrix_len==0 {
129 return Err("Invalid Padding Length".into());
130 }
131 for i in 0..matrix_len {
132 let seed = matrix.get(i+1)
133 .map(|b| b[0] as u64)
134 .unwrap_or(key_bytes[0] as u64);
135 shuffle(&mut matrix[i], seed.wrapping_add(seed_random),2);
136 }
137
138 mix(matrix_size,&mut padded_text, &key_bytes);
139 let seed_random=(seed_random as u16).to_be_bytes();
140 padded_text.push(seed_random[0]);
141 padded_text.push(seed_random[1]);
142 Ok(padded_text)
143 }
144
145
146 /// Encrypts raw bytes using the provided key.
147 ///
148 /// # Arguments
149 /// * `text` - The plaintext to encrypt
150 /// * `key` - The encryption key
151 ///
152 /// # Returns
153 /// A `Result` URL-safe base64 string without padding or an error if encryption fails.
154 ///
155 /// # Example
156 /// ```
157 /// use crypt_ro::Cryptor;
158 ///
159 /// let cryptor = Cryptor::new();
160 /// let encrypted = cryptor.encrypt_text("secret message", "password").unwrap();
161 /// assert!(!encrypted.contains('/')); // URL-safe
162 pub fn encrypt_text(&self, text: &str, key: &str) -> Result<String, Box<dyn Error>> {
163 Ok(URL_SAFE.encode(self.encrypt(text.as_bytes(), key)?).trim_end_matches('=').to_string())
164 }
165
166 /// Decrypts bytes using the provided key.
167 ///
168 /// # Arguments
169 /// * `encoded` - The encrypted bytes to decrypt
170 /// * `key` - The decryption key
171 ///
172 /// # Returns
173 /// A `Result` containing the decrypted bytes or an error if decryption fails.
174 ///
175 /// # Example
176 /// ```
177 /// use crypt_ro::Cryptor;
178 ///
179 /// let cryptor = Cryptor::new();
180 /// let encrypted = cryptor.encrypt(b"data", "key").unwrap();
181 /// let decrypted = cryptor.decrypt(&encrypted, "key").unwrap();
182 /// assert_eq!(decrypted, b"data");
183 /// ```
184 pub fn decrypt(&self, encoded: &Vec<u8>, key: &str) -> Result<Vec<u8>, Box<dyn Error>> {
185 let len=encoded.len();
186 if len < 6 {
187 return Err("Invalid Token Matrix Length".into());
188 }
189
190 let seed_random=u16::from_be_bytes([encoded[len - 2],encoded[len - 1]]) as u64;
191 let mut decoded = encoded[..len-2].to_vec();
192 let len=len-2;
193 let matrix_size=self.matrix;
194
195 let key_bytes = generate_password(matrix_size,key.as_bytes());
196 unmix(matrix_size,&mut decoded, &key_bytes);
197 let mut matrix = decoded.chunks_exact_mut(matrix_size).collect::<Vec<_>>();
198 let matrix_len=matrix.len();
199 for i in (0..matrix_len).rev() {
200 let seed = matrix.get(i+1)
201 .map(|b| b[0] as u64)
202 .unwrap_or(key_bytes[0] as u64);
203 unshuffle(&mut matrix[i], seed.wrapping_add(seed_random),2);
204 }
205
206 let seed_sum: u64 = key_bytes.iter().map(|&b| b as u64).sum();
207 unshuffle(&mut decoded, seed_sum.wrapping_add(seed_random),5);
208
209 let data_size = u32::from_be_bytes([decoded[0], decoded[1], decoded[2], decoded[3]]) as usize;
210 if len < data_size+10 {
211 return Err("Invalid Token Matrix Length".into());
212 }
213 let result_bytes = &decoded[10..data_size+10];
214 Ok(result_bytes.to_vec())
215 }
216
217 /// Decrypts a URL-safe base64 encoded string using the provided key.
218 ///
219 /// # Arguments
220 /// * `encoded` - A URL-safe base64 encoded string to decrypt
221 /// * `key` - The decryption key
222 ///
223 /// # Returns
224 /// A `Result` containing the decrypted string or an error if decryption fails.
225 ///
226 /// # Example
227 /// ```
228 /// use crypt_ro::Cryptor;
229 ///
230 /// let cryptor = Cryptor::new();
231 /// let encrypted = cryptor.encrypt_text("message", "pass").unwrap();
232 /// let decrypted = cryptor.decrypt_text(&encrypted, "pass").unwrap();
233 /// assert_eq!(decrypted, "message");
234 /// ```
235 pub fn decrypt_text(&self, encoded: &str, key: &str) -> Result<String, Box<dyn Error>> {
236 let mut input = encoded.to_string();
237 let padding = input.len() % 4;
238 if padding != 0 {
239 input.push_str(&"=".repeat(4 - padding));
240 }
241
242 let data = URL_SAFE.decode(&input)?;
243 let result = String::from_utf8(self.decrypt(&data, &key)?)?
244 .to_string();
245 Ok(result)
246 }
247
248 /// Sets the matrix size used for cryptographic operations.
249 ///
250 /// The matrix size determines how data is chunked and processed during encryption/decryption.
251 /// Must be a positive non-zero value.
252 ///
253 /// # Example
254 /// ```
255 /// use crypt_ro::Cryptor;
256 ///
257 /// let mut cryptor = Cryptor::new();
258 /// cryptor.set_matrix(64); // Use larger blocks
259 /// ```
260 pub fn set_matrix(&mut self, size: usize) {
261 if size>0{
262 self.matrix = size;
263 }
264 }
265}