1 // Copyright (C) 2022 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use std::{fs::File, io::Read};
16 
17 use anyhow::{ensure, Context, Result};
18 use log::debug;
19 use tokio::io::AsyncReadExt;
20 
21 use crate::drbg;
22 
23 const SEED_FOR_CLIENT_LEN: usize = 496;
24 const NUM_REQUESTS_PER_RESEED: u32 = 256;
25 
26 pub struct ConditionerBuilder {
27     hwrng: File,
28     rg: drbg::Drbg,
29 }
30 
31 impl ConditionerBuilder {
new(mut hwrng: File) -> Result<ConditionerBuilder>32     pub fn new(mut hwrng: File) -> Result<ConditionerBuilder> {
33         let mut et: drbg::Entropy = [0; drbg::ENTROPY_LEN];
34         hwrng.read_exact(&mut et).context("hwrng.read_exact in new")?;
35         let rg = drbg::Drbg::new(&et)?;
36         Ok(ConditionerBuilder { hwrng, rg })
37     }
38 
build(self) -> Conditioner39     pub fn build(self) -> Conditioner {
40         Conditioner {
41             hwrng: tokio::fs::File::from_std(self.hwrng),
42             rg: self.rg,
43             requests_since_reseed: 0,
44         }
45     }
46 }
47 
48 pub struct Conditioner {
49     hwrng: tokio::fs::File,
50     rg: drbg::Drbg,
51     requests_since_reseed: u32,
52 }
53 
54 impl Conditioner {
reseed_if_necessary(&mut self) -> Result<()>55     pub async fn reseed_if_necessary(&mut self) -> Result<()> {
56         if self.requests_since_reseed >= NUM_REQUESTS_PER_RESEED {
57             debug!("Reseeding DRBG");
58             let mut et: drbg::Entropy = [0; drbg::ENTROPY_LEN];
59             self.hwrng.read_exact(&mut et).await.context("hwrng.read_exact in reseed")?;
60             self.rg.reseed(&et)?;
61             self.requests_since_reseed = 0;
62         }
63         Ok(())
64     }
65 
request(&mut self) -> Result<[u8; SEED_FOR_CLIENT_LEN]>66     pub fn request(&mut self) -> Result<[u8; SEED_FOR_CLIENT_LEN]> {
67         ensure!(self.requests_since_reseed < NUM_REQUESTS_PER_RESEED, "Not enough reseeds");
68         let mut seed_for_client = [0u8; SEED_FOR_CLIENT_LEN];
69         self.rg.generate(&mut seed_for_client)?;
70         self.requests_since_reseed += 1;
71         Ok(seed_for_client)
72     }
73 }
74