• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, os::unix::io::AsRawFd};
16 
17 use anyhow::{ensure, Context, Result};
18 use log::debug;
19 use nix::fcntl::{fcntl, FcntlArg::F_SETFL, OFlag};
20 use tokio::io::AsyncReadExt;
21 
22 use crate::drbg;
23 
24 const SEED_FOR_CLIENT_LEN: usize = 496;
25 const NUM_REQUESTS_PER_RESEED: u32 = 256;
26 
27 pub struct ConditionerBuilder {
28     hwrng: File,
29     rg: drbg::Drbg,
30 }
31 
32 impl ConditionerBuilder {
new(mut hwrng: File) -> Result<ConditionerBuilder>33     pub fn new(mut hwrng: File) -> Result<ConditionerBuilder> {
34         let mut et: drbg::Entropy = [0; drbg::ENTROPY_LEN];
35         hwrng.read_exact(&mut et).context("hwrng.read_exact in new")?;
36         let rg = drbg::Drbg::new(&et)?;
37         fcntl(hwrng.as_raw_fd(), F_SETFL(OFlag::O_NONBLOCK))
38             .context("setting O_NONBLOCK on hwrng")?;
39         Ok(ConditionerBuilder { hwrng, rg })
40     }
41 
build(self) -> Conditioner42     pub fn build(self) -> Conditioner {
43         Conditioner {
44             hwrng: tokio::fs::File::from_std(self.hwrng),
45             rg: self.rg,
46             requests_since_reseed: 0,
47         }
48     }
49 }
50 
51 pub struct Conditioner {
52     hwrng: tokio::fs::File,
53     rg: drbg::Drbg,
54     requests_since_reseed: u32,
55 }
56 
57 impl Conditioner {
reseed_if_necessary(&mut self) -> Result<()>58     pub async fn reseed_if_necessary(&mut self) -> Result<()> {
59         if self.requests_since_reseed >= NUM_REQUESTS_PER_RESEED {
60             debug!("Reseeding DRBG");
61             let mut et: drbg::Entropy = [0; drbg::ENTROPY_LEN];
62             self.hwrng.read_exact(&mut et).await.context("hwrng.read_exact in reseed")?;
63             self.rg.reseed(&et)?;
64             self.requests_since_reseed = 0;
65         }
66         Ok(())
67     }
68 
request(&mut self) -> Result<[u8; SEED_FOR_CLIENT_LEN]>69     pub fn request(&mut self) -> Result<[u8; SEED_FOR_CLIENT_LEN]> {
70         ensure!(self.requests_since_reseed < NUM_REQUESTS_PER_RESEED, "Not enough reseeds");
71         let mut seed_for_client = [0u8; SEED_FOR_CLIENT_LEN];
72         self.rg.generate(&mut seed_for_client)?;
73         self.requests_since_reseed += 1;
74         Ok(seed_for_client)
75     }
76 }
77