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}