scirs2_core/random/
secure.rs1use crate::random::core::Random;
8use rand::rngs::StdRng;
9use rand::{Rng, RngExt, 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
280fn hex_encode(bytes: &[u8]) -> String {
284 const HEX_CHARS: &[u8; 16] = b"0123456789abcdef";
285 let mut out = String::with_capacity(bytes.len() * 2);
286 for &byte in bytes {
287 out.push(HEX_CHARS[usize::from(byte >> 4)] as char);
288 out.push(HEX_CHARS[usize::from(byte & 0x0f)] as char);
289 }
290 out
291}
292
293#[cfg(test)]
294mod tests {
295 use super::*;
296
297 #[test]
298 fn test_secure_random_creation() {
299 let mut secure_rng = SecureRandom::new();
300 let value = secure_rng.random_f64();
301 assert!((0.0..1.0).contains(&value));
302 }
303
304 #[test]
305 fn test_secure_random_bytes() {
306 let mut secure_rng = SecureRandom::new();
307 let bytes = secure_rng.random_bytes(32);
308 assert_eq!(bytes.len(), 32);
309 }
310
311 #[test]
312 fn test_secure_key_generation() {
313 let mut secure_rng = SecureRandom::new();
314 let key = secure_rng.generate_key(16);
315 assert_eq!(key.len(), 16);
316 }
317
318 #[test]
319 fn test_secure_alphanumeric() {
320 let mut secure_rng = SecureRandom::new();
321 let text = secure_rng.random_alphanumeric(20);
322 assert_eq!(text.len(), 20);
323 assert!(text.chars().all(|c| c.is_alphanumeric()));
324 }
325
326 #[test]
327 fn test_hex_encode() {
328 assert_eq!(hex_encode(&[]), "");
329 assert_eq!(hex_encode(&[0x00]), "00");
330 assert_eq!(hex_encode(&[0xff]), "ff");
331 assert_eq!(hex_encode(&[0xde, 0xad, 0xbe, 0xef]), "deadbeef");
332 assert_eq!(hex_encode(&[0x01, 0x0a, 0x10, 0x7f]), "010a107f");
333 }
334
335 #[test]
336 fn test_secure_hex() {
337 let mut secure_rng = SecureRandom::new();
338 let hex = secure_rng.random_hex(16);
339 assert_eq!(hex.len(), 32); assert!(hex.chars().all(|c| c.is_ascii_hexdigit()));
341 }
342
343 #[test]
344 fn test_secure_uuid() {
345 let mut secure_rng = SecureRandom::new();
346 let uuid = secure_rng.random_uuid();
347
348 println!("Generated UUID: '{}' (length: {})", uuid, uuid.len());
349
350 assert_eq!(
352 uuid.len(),
353 36,
354 "UUID should be 36 characters, got: '{}'",
355 uuid
356 );
357 assert_eq!(uuid.chars().nth(8).expect("Operation failed"), '-');
358 assert_eq!(uuid.chars().nth(13).expect("Operation failed"), '-');
359 assert_eq!(uuid.chars().nth(18).expect("Operation failed"), '-');
360 assert_eq!(uuid.chars().nth(23).expect("Operation failed"), '-');
361 }
362
363 #[test]
364 fn test_secure_rng_pool() {
365 let pool = SecureRngPool::new();
366 let mut rng = pool.get_secure_rng();
367 let value = rng.random_f64();
368 assert!((0.0..1.0).contains(&value));
369 }
370
371 #[test]
372 fn test_secure_utils() {
373 let salt = utils::generate_salt(16);
374 assert_eq!(salt.len(), 16);
375
376 let session_id = utils::generate_session_id();
377 assert_eq!(session_id.len(), 32);
378
379 let api_key = utils::generate_api_key(24);
380 assert_eq!(api_key.len(), 48); let password = utils::generate_password(12, false);
383 assert_eq!(password.len(), 12);
384
385 let password_with_symbols = utils::generate_password(12, true);
386 assert_eq!(password_with_symbols.len(), 12);
387
388 let iv = utils::generate_iv(16);
389 assert_eq!(iv.len(), 16);
390 }
391
392 #[test]
393 fn test_secure_random_range() {
394 let mut secure_rng = SecureRandom::new();
395
396 for _ in 0..100 {
397 let value = secure_rng.random_range(10, 20);
398 assert!((10..20).contains(&value));
399 }
400 }
401
402 #[test]
403 fn test_secure_random_bool() {
404 let mut secure_rng = SecureRandom::new();
405
406 let _bool_val = secure_rng.random_bool();
408
409 let always_true = secure_rng.random_bool_with_probability(1.0);
411 assert!(always_true);
412
413 let always_false = secure_rng.random_bool_with_probability(0.0);
414 assert!(!always_false);
415 }
416}