1 // Copyright 2021, 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 //! This module holds functionality for retrieving and distributing entropy.
16 
17 use anyhow::{Context, Result};
18 use log::error;
19 use std::time::{Duration, Instant};
20 
21 static ENTROPY_SIZE: usize = 64;
22 static MIN_FEED_INTERVAL_SECS: u64 = 30;
23 
24 #[derive(Default)]
25 struct FeederInfo {
26     last_feed: Option<Instant>,
27 }
28 
29 /// Register the entropy feeder as an idle callback.
register_feeder()30 pub fn register_feeder() {
31     crate::globals::ASYNC_TASK.add_idle(|shelf| {
32         let mut info = shelf.get_mut::<FeederInfo>();
33         let now = Instant::now();
34         let feed_needed = match info.last_feed {
35             None => true,
36             Some(last) => now.duration_since(last) > Duration::from_secs(MIN_FEED_INTERVAL_SECS),
37         };
38         if feed_needed {
39             info.last_feed = Some(now);
40             feed_devices();
41         }
42     });
43 }
44 
get_entropy(size: usize) -> Result<Vec<u8>>45 fn get_entropy(size: usize) -> Result<Vec<u8>> {
46     keystore2_crypto::generate_random_data(size).context("Retrieving entropy for KeyMint device")
47 }
48 
49 /// Feed entropy to all known KeyMint devices.
feed_devices()50 pub fn feed_devices() {
51     let km_devs = crate::globals::get_keymint_devices();
52     if km_devs.is_empty() {
53         return;
54     }
55     let data = match get_entropy(km_devs.len() * ENTROPY_SIZE) {
56         Ok(data) => data,
57         Err(e) => {
58             error!(
59                 "Failed to retrieve {}*{} bytes of entropy: {:?}",
60                 km_devs.len(),
61                 ENTROPY_SIZE,
62                 e
63             );
64             return;
65         }
66     };
67     for (i, km_dev) in km_devs.iter().enumerate() {
68         let offset = i * ENTROPY_SIZE;
69         let sub_data = &data[offset..(offset + ENTROPY_SIZE)];
70         if let Err(e) = km_dev.addRngEntropy(sub_data) {
71             error!("Failed to feed entropy to KeyMint device: {:?}", e);
72         }
73     }
74 }
75 
76 #[cfg(test)]
77 mod tests {
78     use super::*;
79     use std::collections::HashSet;
80 
81     #[test]
test_entropy_size()82     fn test_entropy_size() {
83         for size in &[0, 1, 4, 8, 256, 4096] {
84             let data = get_entropy(*size).expect("failed to get entropy");
85             assert_eq!(data.len(), *size);
86         }
87     }
88     #[test]
test_entropy_uniqueness()89     fn test_entropy_uniqueness() {
90         let count = 10;
91         let mut seen = HashSet::new();
92         for _i in 0..count {
93             let data = get_entropy(16).expect("failed to get entropy");
94             seen.insert(data);
95         }
96         assert_eq!(seen.len(), count);
97     }
98 }
99