scirs2_core/random/
secure.rs1use crate::random::core::Random;
8use rand::rngs::StdRng;
9use rand::{Rng, SeedableRng};
10use rand_distr::{Distribution, Uniform};
11use std::collections::hash_map::DefaultHasher;
12use std::hash::{Hash, Hasher};
13use std::process;
14use std::thread;
15use std::time::{SystemTime, UNIX_EPOCH};
16
17pub struct SecureRandom {
22 rng: Random<StdRng>,
23}
24
25impl Default for SecureRandom {
26 fn default() -> Self {
27 Self::new()
28 }
29}
30
31impl SecureRandom {
32 pub fn new() -> Self {
40 let time_nanos = SystemTime::now()
42 .duration_since(UNIX_EPOCH)
43 .map(|d| d.as_nanos())
44 .unwrap_or(0);
45
46 let process_id = process::id() as u128;
47 let thread_id = thread::current().id();
48
49 let mut hasher = DefaultHasher::new();
51 time_nanos.hash(&mut hasher);
52 process_id.hash(&mut hasher);
53 thread_id.hash(&mut hasher);
54
55 let seed_u64 = hasher.finish();
56
57 let mut seed = [0u8; 32];
59 for (i, chunk) in seed.chunks_mut(8).enumerate() {
60 let offset_seed = seed_u64.wrapping_add((i as u64).wrapping_mul(0x9E3779B97F4A7C15));
61 let bytes = offset_seed.to_le_bytes();
62 chunk.copy_from_slice(&bytes[..chunk.len()]);
63 }
64
65 let std_rng = StdRng::from_seed(seed);
66 Self {
67 rng: Random { rng: std_rng },
68 }
69 }
70
71 pub fn from_seed(seed: [u8; 32]) -> Self {
78 let std_rng = StdRng::from_seed(seed);
79 Self {
80 rng: Random { rng: std_rng },
81 }
82 }
83
84 pub fn sample<D, T>(&mut self, distribution: D) -> T
86 where
87 D: Distribution<T>,
88 {
89 self.rng.sample(distribution)
90 }
91
92 pub fn random_bytes(&mut self, count: usize) -> Vec<u8> {
96 (0..count)
97 .map(|_| self.sample(Uniform::new(0u8, 255u8).expect("Operation failed")))
98 .collect()
99 }
100
101 pub fn generate_key(&mut self, length: usize) -> Vec<u8> {
105 self.random_bytes(length)
106 }
107
108 pub fn generate_nonce(&mut self, length: usize) -> Vec<u8> {
113 self.random_bytes(length)
114 }
115
116 pub fn random_f64(&mut self) -> f64 {
118 self.sample(Uniform::new(0.0, 1.0).expect("Operation failed"))
119 }
120
121 pub fn random_f32(&mut self) -> f32 {
123 self.sample(Uniform::new(0.0f32, 1.0f32).expect("Operation failed"))
124 }
125
126 pub fn random_range<T>(&mut self, min: T, max: T) -> T
128 where
129 T: rand_distr::uniform::SampleUniform + PartialOrd + Copy,
130 {
131 self.sample(Uniform::new(min, max).expect("Operation failed"))
132 }
133
134 pub fn random_bool(&mut self) -> bool {
136 self.rng.rng.random_bool(0.5)
137 }
138
139 pub fn random_bool_with_probability(&mut self, p: f64) -> bool {
141 self.rng.rng.random_bool(p)
142 }
143
144 pub fn random_alphanumeric(&mut self, length: usize) -> String {
148 const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
149 (0..length)
150 .map(|_| {
151 let idx = self.random_range(0, CHARSET.len());
152 CHARSET[idx] as char
153 })
154 .collect()
155 }
156
157 pub fn random_hex(&mut self, byte_length: usize) -> String {
161 let bytes = self.random_bytes(byte_length);
162 hex::encode(bytes)
163 }
164
165 pub fn random_uuid(&mut self) -> String {
169 let bytes = self.random_bytes(16);
170 format!(
171 "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-4{:01x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
172 bytes[0], bytes[1], bytes[2], bytes[3],
173 bytes[4], bytes[5],
174 bytes[6] & 0x0f, bytes[7],
175 bytes[8] & 0x3f | 0x80, bytes[9],
176 bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]
177 )
178 }
179
180 pub fn rng_mut(&mut self) -> &mut Random<StdRng> {
182 &mut self.rng
183 }
184}
185
186pub struct SecureRngPool {
191 seed_base: u64,
192}
193
194impl SecureRngPool {
195 pub fn new() -> Self {
197 let time_nanos = SystemTime::now()
198 .duration_since(UNIX_EPOCH)
199 .map(|d| d.as_nanos() as u64)
200 .unwrap_or(0);
201
202 Self {
203 seed_base: time_nanos,
204 }
205 }
206
207 pub fn get_secure_rng(&self) -> SecureRandom {
209 let thread_id = thread::current().id();
210 let mut hasher = DefaultHasher::new();
211 self.seed_base.hash(&mut hasher);
212 thread_id.hash(&mut hasher);
213
214 let thread_seed = hasher.finish();
215 let mut seed = [0u8; 32];
216
217 for (i, chunk) in seed.chunks_mut(8).enumerate() {
218 let offset_seed = thread_seed.wrapping_add((i as u64).wrapping_mul(0x9E3779B97F4A7C15));
219 let bytes = offset_seed.to_le_bytes();
220 chunk.copy_from_slice(&bytes[..chunk.len()]);
221 }
222
223 SecureRandom::from_seed(seed)
224 }
225}
226
227impl Default for SecureRngPool {
228 fn default() -> Self {
229 Self::new()
230 }
231}
232
233pub mod utils {
235 use super::*;
236
237 pub fn generate_salt(length: usize) -> Vec<u8> {
239 let mut rng = SecureRandom::new();
240 rng.random_bytes(length)
241 }
242
243 pub fn generate_session_id() -> String {
245 let mut rng = SecureRandom::new();
246 rng.random_alphanumeric(32)
247 }
248
249 pub fn generate_api_key(length: usize) -> String {
251 let mut rng = SecureRandom::new();
252 rng.random_hex(length)
253 }
254
255 pub fn generate_password(length: usize, include_symbols: bool) -> String {
257 let mut rng = SecureRandom::new();
258
259 let charset: &[u8] = if include_symbols {
260 b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+-=[]{}|;:,.<>?"
261 } else {
262 b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
263 };
264
265 (0..length)
266 .map(|_| {
267 let idx = rng.random_range(0, charset.len());
268 charset[idx] as char
269 })
270 .collect()
271 }
272
273 pub fn generate_iv(length: usize) -> Vec<u8> {
275 let mut rng = SecureRandom::new();
276 rng.random_bytes(length)
277 }
278}
279
280mod hex {
282 pub fn encode(bytes: Vec<u8>) -> String {
283 bytes.iter().map(|b| format!("{:02x}", b)).collect()
284 }
285}
286
287#[cfg(test)]
288mod tests {
289 use super::*;
290
291 #[test]
292 fn test_secure_random_creation() {
293 let mut secure_rng = SecureRandom::new();
294 let value = secure_rng.random_f64();
295 assert!((0.0..1.0).contains(&value));
296 }
297
298 #[test]
299 fn test_secure_random_bytes() {
300 let mut secure_rng = SecureRandom::new();
301 let bytes = secure_rng.random_bytes(32);
302 assert_eq!(bytes.len(), 32);
303 }
304
305 #[test]
306 fn test_secure_key_generation() {
307 let mut secure_rng = SecureRandom::new();
308 let key = secure_rng.generate_key(16);
309 assert_eq!(key.len(), 16);
310 }
311
312 #[test]
313 fn test_secure_alphanumeric() {
314 let mut secure_rng = SecureRandom::new();
315 let text = secure_rng.random_alphanumeric(20);
316 assert_eq!(text.len(), 20);
317 assert!(text.chars().all(|c| c.is_alphanumeric()));
318 }
319
320 #[test]
321 fn test_secure_hex() {
322 let mut secure_rng = SecureRandom::new();
323 let hex = secure_rng.random_hex(16);
324 assert_eq!(hex.len(), 32); assert!(hex.chars().all(|c| c.is_ascii_hexdigit()));
326 }
327
328 #[test]
329 fn test_secure_uuid() {
330 let mut secure_rng = SecureRandom::new();
331 let uuid = secure_rng.random_uuid();
332
333 println!("Generated UUID: '{}' (length: {})", uuid, uuid.len());
334
335 assert_eq!(
337 uuid.len(),
338 36,
339 "UUID should be 36 characters, got: '{}'",
340 uuid
341 );
342 assert_eq!(uuid.chars().nth(8).expect("Operation failed"), '-');
343 assert_eq!(uuid.chars().nth(13).expect("Operation failed"), '-');
344 assert_eq!(uuid.chars().nth(18).expect("Operation failed"), '-');
345 assert_eq!(uuid.chars().nth(23).expect("Operation failed"), '-');
346 }
347
348 #[test]
349 fn test_secure_rng_pool() {
350 let pool = SecureRngPool::new();
351 let mut rng = pool.get_secure_rng();
352 let value = rng.random_f64();
353 assert!((0.0..1.0).contains(&value));
354 }
355
356 #[test]
357 fn test_secure_utils() {
358 let salt = utils::generate_salt(16);
359 assert_eq!(salt.len(), 16);
360
361 let session_id = utils::generate_session_id();
362 assert_eq!(session_id.len(), 32);
363
364 let api_key = utils::generate_api_key(24);
365 assert_eq!(api_key.len(), 48); let password = utils::generate_password(12, false);
368 assert_eq!(password.len(), 12);
369
370 let password_with_symbols = utils::generate_password(12, true);
371 assert_eq!(password_with_symbols.len(), 12);
372
373 let iv = utils::generate_iv(16);
374 assert_eq!(iv.len(), 16);
375 }
376
377 #[test]
378 fn test_secure_random_range() {
379 let mut secure_rng = SecureRandom::new();
380
381 for _ in 0..100 {
382 let value = secure_rng.random_range(10, 20);
383 assert!((10..20).contains(&value));
384 }
385 }
386
387 #[test]
388 fn test_secure_random_bool() {
389 let mut secure_rng = SecureRandom::new();
390
391 let _bool_val = secure_rng.random_bool();
393
394 let always_true = secure_rng.random_bool_with_probability(1.0);
396 assert!(always_true);
397
398 let always_false = secure_rng.random_bool_with_probability(0.0);
399 assert!(!always_false);
400 }
401}