kernel/hil/entropy.rs
1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Interfaces for accessing an entropy source.
6//!
7//! An entropy source produces random bits that are computationally
8//! intractable to guess, even if the complete history of generated
9//! bits and state of the device can be observed. Entropy sources must
10//! generate bits from an underlying physical random process, such as
11//! thermal noise, radiation, avalanche noise, or circuit
12//! instability. These bits of entropy can be used to seed
13//! cryptographically strong random number generators. Because high-quality
14//! entropy is critical for security and these APIs provide entropy,
15//! it is important to understand all of these requirements before
16//! implementing these traits. Otherwise you may subvert the security
17//! of the operating system.
18//!
19//! _Entropy_: Entropy bits generated by this trait MUST have very high
20//! entropy, i.e. 1 bit of entropy per generated bit. If the underlying
21//! source generates <1 bit of entropy per bit, these low-entropy bits
22//! SHOULD be mixed and combined with a cryptographic hash function.
23//! A good, short reference on the difference between entropy and
24//! randomness as well as guidelines for high-entropy sources is
25//! Recommendations for Randomness in the Operating System: How to
26//! Keep Evil Children Out of Your Pool and Other Random Facts,
27//! Corrigan-Gibbs et al., HotOS 2015.
28//!
29//! The interface is designed to work well with entropy generators
30//! that may not have values ready immediately. This is important when
31//! generating numbers from a low-bandwidth hardware entropy source
32//! generator or when virtualized among many consumers.
33//!
34//! Entropy is yielded to a Client as an `Iterator` which only
35//! terminates when no more entropy is currently available. Clients
36//! can request more entropy if needed and will be called again when
37//! more is available.
38//!
39//! # Example
40//!
41//! The following example is a simple capsule that prints out entropy
42//! once a second using the `Alarm` and `Entropy` traits.
43//!
44//! ```
45//! use kernel::hil;
46//! use kernel::hil::entropy::Entropy32;
47//! use kernel::hil::entropy::Client32;
48//! use kernel::hil::time::Alarm;
49//! use kernel::hil::time::ConvertTicks;
50//! use kernel::hil::time::Frequency;
51//! use kernel::hil::time::AlarmClient;
52//! use kernel::ErrorCode;
53//!
54//! struct EntropyTest<'a, A: 'a + Alarm<'a>> {
55//! entropy: &'a dyn Entropy32 <'a>,
56//! alarm: &'a A
57//! }
58//!
59//! impl<'a, A: Alarm<'a>> EntropyTest<'a, A> {
60//! pub fn initialize(&self) {
61//! let now = self.alarm.now();
62//! let dt = self.alarm.ticks_from_seconds(1);
63//! self.alarm.set_alarm(now, dt);
64//! }
65//! }
66//!
67//! impl<'a, A: Alarm<'a>> AlarmClient for EntropyTest<'a, A> {
68//! fn alarm(&self) {
69//! self.entropy.get();
70//! }
71//! }
72//!
73//! impl<'a, A: Alarm<'a>> Client32 for EntropyTest<'a, A> {
74//! fn entropy_available(&self,
75//! entropy: &mut dyn Iterator<Item = u32>,
76//! error: Result<(), ErrorCode>) -> hil::entropy::Continue {
77//! match entropy.next() {
78//! Some(val) => {
79//! println!("Entropy {}", val);
80//! let now = self.alarm.now();
81//! let dt = self.alarm.ticks_from_seconds(1);
82//! self.alarm.set_alarm(now, dt);
83//! hil::entropy::Continue::Done
84//! },
85//! None => hil::entropy::Continue::More
86//! }
87//! }
88//! }
89//! ```
90
91use crate::ErrorCode;
92
93/// Denotes whether the [Client](trait.Client.html) wants to be notified when
94/// `More` randomness is available or if they are `Done`
95#[derive(Debug, Eq, PartialEq)]
96pub enum Continue {
97 /// More randomness is required.
98 More,
99 /// No more randomness required.
100 Done,
101}
102
103/// Generic interface for a 32-bit entropy source.
104///
105/// Implementors should assume the client implements the
106/// [Client](trait.Client32.html) trait.
107pub trait Entropy32<'a> {
108 /// Initiate the acquisition of entropy.
109 ///
110 /// There are three valid return values:
111 /// - Ok(()): a `entropy_available` callback will be called in
112 /// the future when entropy is available.
113 /// - FAIL: a `entropy_available` callback will not be called in
114 /// the future, because entropy cannot be generated. This
115 /// is a general failure condition.
116 /// - OFF: a `entropy_available` callback will not be called in
117 /// the future, because the random number generator is off/not
118 /// powered.
119 fn get(&self) -> Result<(), ErrorCode>;
120
121 /// Cancel acquisition of entropy.
122 ///
123 /// There are three valid return values:
124 /// - Ok(()): an outstanding request from `get` has been cancelled,
125 /// or there was no outstanding request. No `entropy_available`
126 /// callback will be issued.
127 /// - FAIL: There will be a `entropy_available` callback, which
128 /// may or may not return an error code.
129 fn cancel(&self) -> Result<(), ErrorCode>;
130
131 /// Set the client to receive `entropy_available` callbacks.
132 fn set_client(&'a self, _: &'a dyn Client32);
133}
134
135/// An [Entropy32](trait.Entropy32.html) client
136///
137/// Clients of an [Entropy32](trait.Entropy32.html) must implement this trait.
138pub trait Client32 {
139 /// Called by the (Entropy)[trait.Entropy32.html] when there is entropy
140 /// available.
141 ///
142 /// `entropy` in an `Iterator` of available entropy. The amount of
143 /// entropy available may increase if `entropy` is not consumed
144 /// quickly so clients should not rely on iterator termination to
145 /// finish consuming entropy.
146 ///
147 /// The client returns either `Continue::More` if the iterator did
148 /// not have enough entropy (indicating another
149 /// `entropy_available` callback is requested) and the client
150 /// would like to be called again when more is available, or
151 /// `Continue::Done`, which indicates `entropy_available` should
152 /// not be called again until `get()` is called.
153 ///
154 /// If `entropy_available` is triggered after a call to `cancel()`
155 /// then error MUST be CANCEL and `entropy` MAY contain bits of
156 /// entropy.
157 fn entropy_available(
158 &self,
159 entropy: &mut dyn Iterator<Item = u32>,
160 error: Result<(), ErrorCode>,
161 ) -> Continue;
162}
163
164/// An 8-bit entropy generator.
165///
166/// Implementors should assume the client implements the
167/// [Client8](trait.Client8.html) trait.
168pub trait Entropy8<'a> {
169 /// Initiate the acquisition of new entropy.
170 ///
171 /// There are three valid return values:
172 /// - Ok(()): a `entropy_available` callback will be called in
173 /// the future when entropy is available.
174 /// - FAIL: a `entropy_available` callback will not be called in
175 /// the future, because entropy cannot be generated. This
176 /// is a general failure condition.
177 /// - OFF: a `entropy_available` callback will not be called in
178 /// the future, because the entropy generator is off/not
179 /// powered.
180 fn get(&self) -> Result<(), ErrorCode>;
181
182 /// Cancel acquisition of entropy.
183 ///
184 /// There are three valid return values:
185 /// - Ok(()): an outstanding request from `get` has been cancelled,
186 /// or there was no outstanding request. No `entropy_available`
187 /// callback will be issued.
188 /// - FAIL:: There will be a `entropy_available` callback, which
189 /// may or may not return an error code.
190 fn cancel(&self) -> Result<(), ErrorCode>;
191
192 /// Set the client to receive `entropy_available` callbacks.
193 fn set_client(&'a self, _: &'a dyn Client8);
194}
195
196/// An [Entropy8](trait.Entropy8.html) client
197///
198/// Clients of an [Entropy8](trait.Entropy8.html) must implement this trait.
199pub trait Client8 {
200 /// Called by the (Entropy)[trait.Entropy8.html] when there are
201 /// one or more bytes of entropy available.
202 ///
203 /// `entropy` in an `Iterator` of available entropy. The amount of
204 /// entropy available may increase if `entropy` is not consumed
205 /// quickly so clients should not rely on iterator termination to
206 /// finish consuming entropy.
207 ///
208 /// The client returns either `Continue::More` if the iterator did
209 /// not have enough entropy (indicating another
210 /// `entropy_available` callback is requested) and the client
211 /// would like to be called again when more is available, or
212 /// `Continue::Done`, which indicates `entropy_available` should
213 /// not be called again until `get()` is called.
214 ///
215 /// If `entropy_available` is triggered after a call to `cancel()`
216 /// then error MUST be CANCEL and `entropy` MAY contain bits of
217 /// entropy.
218 fn entropy_available(
219 &self,
220 entropy: &mut dyn Iterator<Item = u8>,
221 error: Result<(), ErrorCode>,
222 ) -> Continue;
223}