1*e1997b9aSAndroid Build Coastguard Worker // Copyright 2021, The Android Open Source Project
2*e1997b9aSAndroid Build Coastguard Worker //
3*e1997b9aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*e1997b9aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*e1997b9aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*e1997b9aSAndroid Build Coastguard Worker //
7*e1997b9aSAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*e1997b9aSAndroid Build Coastguard Worker //
9*e1997b9aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*e1997b9aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*e1997b9aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e1997b9aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*e1997b9aSAndroid Build Coastguard Worker // limitations under the License.
14*e1997b9aSAndroid Build Coastguard Worker
15*e1997b9aSAndroid Build Coastguard Worker //! This module holds functionality for retrieving and distributing entropy.
16*e1997b9aSAndroid Build Coastguard Worker
17*e1997b9aSAndroid Build Coastguard Worker use anyhow::{Context, Result};
18*e1997b9aSAndroid Build Coastguard Worker use log::error;
19*e1997b9aSAndroid Build Coastguard Worker use std::time::{Duration, Instant};
20*e1997b9aSAndroid Build Coastguard Worker
21*e1997b9aSAndroid Build Coastguard Worker static ENTROPY_SIZE: usize = 64;
22*e1997b9aSAndroid Build Coastguard Worker static MIN_FEED_INTERVAL_SECS: u64 = 30;
23*e1997b9aSAndroid Build Coastguard Worker
24*e1997b9aSAndroid Build Coastguard Worker #[derive(Default)]
25*e1997b9aSAndroid Build Coastguard Worker struct FeederInfo {
26*e1997b9aSAndroid Build Coastguard Worker last_feed: Option<Instant>,
27*e1997b9aSAndroid Build Coastguard Worker }
28*e1997b9aSAndroid Build Coastguard Worker
29*e1997b9aSAndroid Build Coastguard Worker /// Register the entropy feeder as an idle callback.
register_feeder()30*e1997b9aSAndroid Build Coastguard Worker pub fn register_feeder() {
31*e1997b9aSAndroid Build Coastguard Worker crate::globals::ASYNC_TASK.add_idle(|shelf| {
32*e1997b9aSAndroid Build Coastguard Worker let info = shelf.get_mut::<FeederInfo>();
33*e1997b9aSAndroid Build Coastguard Worker let now = Instant::now();
34*e1997b9aSAndroid Build Coastguard Worker let feed_needed = match info.last_feed {
35*e1997b9aSAndroid Build Coastguard Worker None => true,
36*e1997b9aSAndroid Build Coastguard Worker Some(last) => now.duration_since(last) > Duration::from_secs(MIN_FEED_INTERVAL_SECS),
37*e1997b9aSAndroid Build Coastguard Worker };
38*e1997b9aSAndroid Build Coastguard Worker if feed_needed {
39*e1997b9aSAndroid Build Coastguard Worker info.last_feed = Some(now);
40*e1997b9aSAndroid Build Coastguard Worker feed_devices();
41*e1997b9aSAndroid Build Coastguard Worker }
42*e1997b9aSAndroid Build Coastguard Worker });
43*e1997b9aSAndroid Build Coastguard Worker }
44*e1997b9aSAndroid Build Coastguard Worker
get_entropy(size: usize) -> Result<Vec<u8>>45*e1997b9aSAndroid Build Coastguard Worker fn get_entropy(size: usize) -> Result<Vec<u8>> {
46*e1997b9aSAndroid Build Coastguard Worker keystore2_crypto::generate_random_data(size).context("Retrieving entropy for KeyMint device")
47*e1997b9aSAndroid Build Coastguard Worker }
48*e1997b9aSAndroid Build Coastguard Worker
49*e1997b9aSAndroid Build Coastguard Worker /// Feed entropy to all known KeyMint devices.
feed_devices()50*e1997b9aSAndroid Build Coastguard Worker pub fn feed_devices() {
51*e1997b9aSAndroid Build Coastguard Worker let km_devs = crate::globals::get_keymint_devices();
52*e1997b9aSAndroid Build Coastguard Worker if km_devs.is_empty() {
53*e1997b9aSAndroid Build Coastguard Worker return;
54*e1997b9aSAndroid Build Coastguard Worker }
55*e1997b9aSAndroid Build Coastguard Worker let data = match get_entropy(km_devs.len() * ENTROPY_SIZE) {
56*e1997b9aSAndroid Build Coastguard Worker Ok(data) => data,
57*e1997b9aSAndroid Build Coastguard Worker Err(e) => {
58*e1997b9aSAndroid Build Coastguard Worker error!(
59*e1997b9aSAndroid Build Coastguard Worker "Failed to retrieve {}*{} bytes of entropy: {:?}",
60*e1997b9aSAndroid Build Coastguard Worker km_devs.len(),
61*e1997b9aSAndroid Build Coastguard Worker ENTROPY_SIZE,
62*e1997b9aSAndroid Build Coastguard Worker e
63*e1997b9aSAndroid Build Coastguard Worker );
64*e1997b9aSAndroid Build Coastguard Worker return;
65*e1997b9aSAndroid Build Coastguard Worker }
66*e1997b9aSAndroid Build Coastguard Worker };
67*e1997b9aSAndroid Build Coastguard Worker for (i, km_dev) in km_devs.iter().enumerate() {
68*e1997b9aSAndroid Build Coastguard Worker let offset = i * ENTROPY_SIZE;
69*e1997b9aSAndroid Build Coastguard Worker let sub_data = &data[offset..(offset + ENTROPY_SIZE)];
70*e1997b9aSAndroid Build Coastguard Worker if let Err(e) = km_dev.addRngEntropy(sub_data) {
71*e1997b9aSAndroid Build Coastguard Worker error!("Failed to feed entropy to KeyMint device: {:?}", e);
72*e1997b9aSAndroid Build Coastguard Worker }
73*e1997b9aSAndroid Build Coastguard Worker }
74*e1997b9aSAndroid Build Coastguard Worker }
75*e1997b9aSAndroid Build Coastguard Worker
76*e1997b9aSAndroid Build Coastguard Worker #[cfg(test)]
77*e1997b9aSAndroid Build Coastguard Worker mod tests {
78*e1997b9aSAndroid Build Coastguard Worker use super::*;
79*e1997b9aSAndroid Build Coastguard Worker use std::collections::HashSet;
80*e1997b9aSAndroid Build Coastguard Worker
81*e1997b9aSAndroid Build Coastguard Worker #[test]
test_entropy_size()82*e1997b9aSAndroid Build Coastguard Worker fn test_entropy_size() {
83*e1997b9aSAndroid Build Coastguard Worker for size in &[0, 1, 4, 8, 256, 4096] {
84*e1997b9aSAndroid Build Coastguard Worker let data = get_entropy(*size).expect("failed to get entropy");
85*e1997b9aSAndroid Build Coastguard Worker assert_eq!(data.len(), *size);
86*e1997b9aSAndroid Build Coastguard Worker }
87*e1997b9aSAndroid Build Coastguard Worker }
88*e1997b9aSAndroid Build Coastguard Worker #[test]
test_entropy_uniqueness()89*e1997b9aSAndroid Build Coastguard Worker fn test_entropy_uniqueness() {
90*e1997b9aSAndroid Build Coastguard Worker let count = 10;
91*e1997b9aSAndroid Build Coastguard Worker let mut seen = HashSet::new();
92*e1997b9aSAndroid Build Coastguard Worker for _i in 0..count {
93*e1997b9aSAndroid Build Coastguard Worker let data = get_entropy(16).expect("failed to get entropy");
94*e1997b9aSAndroid Build Coastguard Worker seen.insert(data);
95*e1997b9aSAndroid Build Coastguard Worker }
96*e1997b9aSAndroid Build Coastguard Worker assert_eq!(seen.len(), count);
97*e1997b9aSAndroid Build Coastguard Worker }
98*e1997b9aSAndroid Build Coastguard Worker }
99