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