blob: ec1181bd93c71d52b6b332024b22689dce71533e [file] [log] [blame]
Paul Crowley9da969e2022-09-16 23:42:24 +00001// 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
Paul Crowley17885692023-03-09 17:51:58 +000015use std::{fs::File, io::Read};
Paul Crowley9da969e2022-09-16 23:42:24 +000016
Paul Crowley021cf552022-09-28 18:37:43 +000017use anyhow::{ensure, Context, Result};
Paul Crowley9da969e2022-09-16 23:42:24 +000018use log::debug;
19use tokio::io::AsyncReadExt;
20
21use crate::drbg;
22
23const SEED_FOR_CLIENT_LEN: usize = 496;
24const NUM_REQUESTS_PER_RESEED: u32 = 256;
25
Paul Crowley021cf552022-09-28 18:37:43 +000026pub struct ConditionerBuilder {
27 hwrng: File,
28 rg: drbg::Drbg,
29}
30
31impl 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)?;
Paul Crowley021cf552022-09-28 18:37:43 +000036 Ok(ConditionerBuilder { hwrng, rg })
37 }
38
39 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
Paul Crowley9da969e2022-09-16 23:42:24 +000048pub struct Conditioner {
49 hwrng: tokio::fs::File,
50 rg: drbg::Drbg,
51 requests_since_reseed: u32,
52}
53
54impl Conditioner {
Paul Crowley9da969e2022-09-16 23:42:24 +000055 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];
Paul Crowley021cf552022-09-28 18:37:43 +000059 self.hwrng.read_exact(&mut et).await.context("hwrng.read_exact in reseed")?;
Paul Crowley9da969e2022-09-16 23:42:24 +000060 self.rg.reseed(&et)?;
61 self.requests_since_reseed = 0;
62 }
63 Ok(())
64 }
65
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}