chore(csprng): use getrandom as random source for unix seeder

This commit is contained in:
Nicolas Sarlin
2025-09-03 10:38:07 +02:00
committed by Nicolas Sarlin
parent baad6a6b49
commit e2c7359057
5 changed files with 30 additions and 27 deletions

View File

@@ -33,6 +33,7 @@ rand = "0.8"
rayon = "1.11"
serde = { version = "1.0", default-features = false }
wasm-bindgen = "0.2.100"
getrandom = "0.2.8"
[profile.bench]
lto = "fat"

View File

@@ -14,6 +14,7 @@ rust-version = "1.72"
[dependencies]
aes = "0.8.2"
rayon = { workspace = true, optional = true }
getrandom = { workspace = true }
[target.'cfg(target_os = "macos")'.dependencies]
libc = "0.2.133"

View File

@@ -1,12 +1,11 @@
use crate::seeders::{Seed, Seeder};
use std::fs::File;
use std::io::Read;
/// A seeder which uses the `/dev/random` source on unix-like systems.
/// A seeder which uses the system entropy source on unix-like systems.
///
/// If available, this will use `getrandom` or `getentropy` system call. Otherwise it will draw from
/// `/dev/urandom` after successfully polling `/dev/random`.
pub struct UnixSeeder {
counter: u128,
secret: u128,
file: File,
}
impl UnixSeeder {
@@ -15,35 +14,34 @@ impl UnixSeeder {
/// Important:
/// ----------
///
/// This secret is used to ensure the quality of the seed in scenarios where `/dev/random` may
/// be compromised.
/// This secret is used to ensure the quality of the seed in scenarios where the system random
/// source may be compromised.
///
/// The attack hypotheses are as follow:
/// - `/dev/random` output can be predicted by a process running on the machine by just
/// - The kernel random output can be predicted by a process running on the machine by just
/// observing various states of the machine
/// - The attacker cannot read data from the process where `tfhe-csprng` is running
///
/// Using a secret in `tfhe-csprng` allows to generate values that the attacker cannot
/// predict, making this seeder secure on systems were `/dev/random` outputs can be
/// predict, making this seeder secure on systems were the kernel random outputs can be
/// predicted.
pub fn new(secret: u128) -> UnixSeeder {
let file = std::fs::File::open("/dev/random").expect("Failed to open /dev/random .");
let counter = std::time::UNIX_EPOCH
.elapsed()
.expect("Failed to initialize unix seeder.")
.as_nanos();
UnixSeeder {
secret,
counter,
file,
}
UnixSeeder { secret }
}
}
impl Seeder for UnixSeeder {
/// Draws entropy from a system source to seed a CSPRNG.
///
/// It may be blocking at system startup if the kernel entropy pool has not been initialized,
/// but should not be blocking after.
///
/// # Panics
/// This may panic if the `getrandom` system call is not available and no file descriptor is
/// available on the system.
fn seed(&mut self) -> Seed {
let output = self.secret ^ self.counter ^ dev_random(&mut self.file);
self.counter = self.counter.wrapping_add(1);
let output = self.secret ^ get_system_entropy();
Seed(output)
}
@@ -52,11 +50,14 @@ impl Seeder for UnixSeeder {
}
}
fn dev_random(random: &mut File) -> u128 {
fn get_system_entropy() -> u128 {
let mut buf = [0u8; 16];
random
.read_exact(&mut buf[..])
.expect("Failed to read from /dev/random .");
// This will use the getrandom syscall if possible (from linux 3.17). This syscall is not
// vulnerable to fd exhaustion since it directly pulls from kernel entropy sources.
//
// This syscall will use the urandom entropy source but block at startup until it is correctly
// seeded. See <https://www.2uo.de/myths-about-urandom/> for a rational around random/urandom.
getrandom::getrandom(&mut buf).expect("Failed to read entropy from system");
u128::from_ne_bytes(buf)
}

View File

@@ -37,7 +37,7 @@ serde_json = "1.0.96"
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test = "0.3"
wasm-bindgen = { workspace = true }
getrandom = { version = "0.2", features = ["js"] }
getrandom = { workspace = true, features = ["js"] }
[target.'cfg(all(not(target_os = "windows"), not(target_arch = "wasm32")))'.dev-dependencies]
rug = "1.19.1"

View File

@@ -86,7 +86,7 @@ wasm-bindgen-rayon = { version = "1.3.0", optional = true }
js-sys = { version = "0.3", optional = true }
console_error_panic_hook = { version = "0.1.7", optional = true }
serde-wasm-bindgen = { version = "0.6.0", optional = true }
getrandom = { version = "0.2.8", optional = true }
getrandom = { workspace = true, optional = true }
bytemuck = { workspace = true }
tfhe-hpu-backend = { version = "0.2", path = "../backends/tfhe-hpu-backend", optional = true }