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