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)
+    }
+}