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 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