Skip to main content

rns_crypto/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2extern crate alloc;
3
4pub mod bigint;
5pub mod pkcs7;
6pub mod sha256;
7pub mod sha512;
8pub mod hmac;
9pub mod hkdf;
10pub mod aes;
11pub mod aes128;
12pub mod aes256;
13pub mod token;
14pub mod x25519;
15pub mod ed25519;
16pub mod identity;
17
18/// Trait for random number generation.
19/// Callers provide an implementation; in `std` builds this wraps OS randomness.
20pub trait Rng {
21    fn fill_bytes(&mut self, dest: &mut [u8]);
22}
23
24/// Deterministic RNG for testing.
25pub struct FixedRng {
26    bytes: alloc::vec::Vec<u8>,
27    pos: usize,
28}
29
30impl FixedRng {
31    pub fn new(bytes: &[u8]) -> Self {
32        Self {
33            bytes: bytes.to_vec(),
34            pos: 0,
35        }
36    }
37}
38
39impl Rng for FixedRng {
40    fn fill_bytes(&mut self, dest: &mut [u8]) {
41        for b in dest.iter_mut() {
42            *b = self.bytes[self.pos % self.bytes.len()];
43            self.pos += 1;
44        }
45    }
46}
47
48/// OS-backed RNG using getrandom(2) syscall on Linux.
49#[cfg(feature = "std")]
50pub struct OsRng;
51
52#[cfg(feature = "std")]
53impl Rng for OsRng {
54    fn fill_bytes(&mut self, dest: &mut [u8]) {
55        // Use getrandom(2) syscall directly on Linux
56        #[cfg(target_os = "linux")]
57        {
58            let ret = unsafe {
59                libc_getrandom(dest.as_mut_ptr(), dest.len(), 0)
60            };
61            assert!(ret == dest.len() as isize, "getrandom failed");
62        }
63        #[cfg(not(target_os = "linux"))]
64        {
65            // Fallback: read from /dev/urandom
66            use std::io::Read;
67            let mut f = std::fs::File::open("/dev/urandom").expect("Failed to open /dev/urandom");
68            f.read_exact(dest).expect("Failed to read from /dev/urandom");
69        }
70    }
71}
72
73#[cfg(all(feature = "std", target_os = "linux"))]
74unsafe fn libc_getrandom(buf: *mut u8, buflen: usize, flags: u32) -> isize {
75    // getrandom syscall number on x86_64 is 318, aarch64 is 278
76    #[cfg(target_arch = "x86_64")]
77    {
78        let ret: isize;
79        core::arch::asm!(
80            "syscall",
81            in("rax") 318u64,
82            in("rdi") buf as u64,
83            in("rsi") buflen as u64,
84            in("rdx") flags as u64,
85            lateout("rax") ret,
86            lateout("rcx") _,
87            lateout("r11") _,
88        );
89        ret
90    }
91    #[cfg(target_arch = "aarch64")]
92    {
93        let ret: isize;
94        core::arch::asm!(
95            "svc #0",
96            in("x8") 278u64,
97            in("x0") buf as u64,
98            in("x1") buflen as u64,
99            in("x2") flags as u64,
100            lateout("x0") ret,
101        );
102        ret
103    }
104    #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
105    {
106        compile_error!("Unsupported architecture for getrandom syscall");
107    }
108}