keyfork/keyfork-entropy/src/lib.rs

64 lines
2.0 KiB
Rust

use std::{fs::{read_dir, read_to_string, File}, io::Read};
static WARNING_LINKS: [&str; 1] =
["https://lore.kernel.org/lkml/20211223141113.1240679-2-Jason@zx2c4.com/"];
fn ensure_safe_kernel_version() {
let kernel_version = read_to_string("/proc/version").expect("/proc/version");
let v = kernel_version
.split(' ')
.nth(2)
.expect("Unable to parse kernel version")
.split('.')
.take(2)
.map(str::parse)
.map(|x| x.expect("Unable to parse kernel version number"))
.collect::<Vec<u32>>();
let [major, minor, ..] = v.as_slice() else {
panic!("Unable to determine major and minor: {kernel_version}");
};
assert!(
[major, minor] > [&5, &4],
"kernel can't generate clean entropy: {}",
WARNING_LINKS[0]
);
}
fn ensure_offline() {
let paths = read_dir("/sys/class/net").expect("Unable to read network interfaces");
for entry in paths {
let mut path = entry.expect("Unable to read directory entry").path();
if path
.as_os_str()
.to_str()
.expect("Unable to decode UTF-8 filepath")
.split('/')
.last()
.expect("No data in file path")
== "lo"
{
continue;
}
path.push("operstate");
let isup = read_to_string(&path).expect("Unable to read operstate of network interfaces");
assert_ne!(isup.trim(), "up", "No network interfaces should be up");
}
}
pub fn ensure_safe() {
if !std::env::vars()
.any(|(name, _)| name == "SHOOT_SELF_IN_FOOT" || name == "INSECURE_HARDWARE_ALLOWED")
{
ensure_safe_kernel_version();
ensure_offline();
}
}
pub fn generate_entropy_of_size(byte_count: usize) -> Result<Vec<u8>, std::io::Error> {
ensure_safe();
let mut vec = vec![0u8; byte_count];
let mut entropy_file = File::open("/dev/urandom")?;
entropy_file.read_exact(&mut vec[..])?;
Ok(vec)
}