Add prng_seeder utility
This binary seeds a FIPS-approved DRBG from /dev/hw_random and then
serves seeds to other processes on the system using a socket
(/dev/socket/prng_seeder) that is passed in by init.
Bug: 243933553
Test: Started under init and verified correct operation using strace
Change-Id: Id4461a402d1ac92180a54cc4b241a2720b94d8de
diff --git a/prng_seeder/src/conditioner.rs b/prng_seeder/src/conditioner.rs
new file mode 100644
index 0000000..66b29a4
--- /dev/null
+++ b/prng_seeder/src/conditioner.rs
@@ -0,0 +1,58 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use std::{fs::File, io::Read};
+
+use anyhow::{ensure, Result};
+use log::debug;
+use tokio::io::AsyncReadExt;
+
+use crate::drbg;
+
+const SEED_FOR_CLIENT_LEN: usize = 496;
+const NUM_REQUESTS_PER_RESEED: u32 = 256;
+
+pub struct Conditioner {
+ hwrng: tokio::fs::File,
+ rg: drbg::Drbg,
+ requests_since_reseed: u32,
+}
+
+impl Conditioner {
+ pub fn new(mut hwrng: File) -> Result<Conditioner> {
+ let mut et: drbg::Entropy = [0; drbg::ENTROPY_LEN];
+ hwrng.read_exact(&mut et)?;
+ let rg = drbg::Drbg::new(&et)?;
+ Ok(Conditioner { hwrng: tokio::fs::File::from_std(hwrng), rg, requests_since_reseed: 0 })
+ }
+
+ pub async fn reseed_if_necessary(&mut self) -> Result<()> {
+ if self.requests_since_reseed >= NUM_REQUESTS_PER_RESEED {
+ debug!("Reseeding DRBG");
+ let mut et: drbg::Entropy = [0; drbg::ENTROPY_LEN];
+ self.hwrng.read_exact(&mut et).await?;
+ self.rg.reseed(&et)?;
+ self.requests_since_reseed = 0;
+ }
+ Ok(())
+ }
+
+ pub fn request(&mut self) -> Result<[u8; SEED_FOR_CLIENT_LEN]> {
+ ensure!(self.requests_since_reseed < NUM_REQUESTS_PER_RESEED, "Not enough reseeds");
+ let mut seed_for_client = [0u8; SEED_FOR_CLIENT_LEN];
+ self.rg.generate(&mut seed_for_client)?;
+ self.requests_since_reseed += 1;
+ Ok(seed_for_client)
+ }
+}