Skip to main content

rns_crypto/
lib.rs

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