oxidite_security/
random.rs

1//! Secure random generation
2
3use rand::Rng;
4use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD};
5
6/// Generate random bytes
7pub fn random_bytes(length: usize) -> Vec<u8> {
8    let mut rng = rand::rng();
9    let mut bytes = vec![0u8; length];
10    rng.fill(&mut bytes[..]);
11    bytes
12}
13
14/// Generate a random hex string
15pub fn random_hex(length: usize) -> String {
16    hex::encode(random_bytes(length))
17}
18
19/// Generate a secure token (URL-safe base64)
20pub fn secure_token(bytes: usize) -> String {
21    URL_SAFE_NO_PAD.encode(random_bytes(bytes))
22}
23
24/// Generate a random alphanumeric string
25pub fn random_alphanumeric(length: usize) -> String {
26    const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
27    let mut rng = rand::rng();
28    
29    (0..length)
30        .map(|_| {
31            let idx = rng.random_range(0..CHARSET.len());
32            CHARSET[idx] as char
33        })
34        .collect()
35}
36
37/// Generate a random number in range
38pub fn random_range(min: u64, max: u64) -> u64 {
39    let mut rng = rand::rng();
40    rng.random_range(min..max)
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46
47    #[test]
48    fn test_random_bytes() {
49        let bytes = random_bytes(32);
50        assert_eq!(bytes.len(), 32);
51    }
52
53    #[test]
54    fn test_random_hex() {
55        let hex_str = random_hex(16);
56        assert_eq!(hex_str.len(), 32); // 16 bytes = 32 hex chars
57    }
58
59    #[test]
60    fn test_secure_token() {
61        let token = secure_token(32);
62        // Base64 encoded 32 bytes is about 43 chars
63        assert!(token.len() > 40);
64    }
65
66    #[test]
67    fn test_random_range() {
68        for _ in 0..100 {
69            let n = random_range(10, 20);
70            assert!(n >= 10 && n < 20);
71        }
72    }
73}