capsules_core/
rng.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//! Library of randomness structures.
6//!
7//! A library for randomness structures including a system call driver
8//! for userspace applications to request randomness, entropy
9//! conversion, entropy to randomness conversion, and synchronous
10//! random number generation.
11//!
12//!
13//! The RNG accepts a user-defined callback and buffer to hold received
14//! randomness. A single command starts the RNG, the callback is called when the
15//! requested amount of randomness is received, or the buffer is filled.
16//!
17//! Usage
18//! -----
19//!
20//! ```rust,ignore
21//! # use kernel::static_init;
22//!
23//! let rng = static_init!(
24//!     capsules::rng::RngDriver<'static, sam4l::trng::Trng>,
25//!     capsules::rng::RngDriver::new(&sam4l::trng::TRNG, board_kernel.create_grant(&grant_cap)),
26//! );
27//! sam4l::trng::TRNG.set_client(rng);
28//! ```
29
30use core::cell::Cell;
31
32use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount};
33use kernel::hil::entropy;
34use kernel::hil::entropy::{Entropy32, Entropy8};
35use kernel::hil::rng;
36use kernel::hil::rng::{Client, Continue, Random, Rng};
37use kernel::processbuffer::WriteableProcessBuffer;
38use kernel::syscall::{CommandReturn, SyscallDriver};
39use kernel::utilities::cells::OptionalCell;
40use kernel::{ErrorCode, ProcessId};
41
42/// Syscall driver number.
43use crate::driver;
44pub const DRIVER_NUM: usize = driver::NUM::Rng as usize;
45
46/// Ids for read-write allow buffers
47mod rw_allow {
48    pub const BUFFER: usize = 0;
49    /// The number of allow buffers the kernel stores for this grant
50    pub const COUNT: u8 = 1;
51}
52
53#[derive(Default)]
54pub struct App {
55    remaining: usize,
56    idx: usize,
57}
58
59pub struct RngDriver<'a, R: Rng<'a>> {
60    rng: &'a R,
61    apps: Grant<App, UpcallCount<1>, AllowRoCount<0>, AllowRwCount<{ rw_allow::COUNT }>>,
62    getting_randomness: Cell<bool>,
63}
64
65impl<'a, R: Rng<'a>> RngDriver<'a, R> {
66    pub fn new(
67        rng: &'a R,
68        grant: Grant<App, UpcallCount<1>, AllowRoCount<0>, AllowRwCount<{ rw_allow::COUNT }>>,
69    ) -> Self {
70        Self {
71            rng,
72            apps: grant,
73            getting_randomness: Cell::new(false),
74        }
75    }
76}
77
78impl<'a, R: Rng<'a>> rng::Client for RngDriver<'a, R> {
79    fn randomness_available(
80        &self,
81        randomness: &mut dyn Iterator<Item = u32>,
82        _error: Result<(), ErrorCode>,
83    ) -> rng::Continue {
84        let mut done = true;
85        for cntr in self.apps.iter() {
86            cntr.enter(|app, kernel_data| {
87                // Check if this app needs random values.
88                if app.remaining > 0 {
89                    // Provide the current application values to the closure
90                    let (oldidx, oldremaining) = (app.idx, app.remaining);
91
92                    let (newidx, newremaining) = kernel_data
93                        .get_readwrite_processbuffer(rw_allow::BUFFER)
94                        .and_then(|buffer| {
95                            buffer.mut_enter(|buffer| {
96                                let mut idx = oldidx;
97                                let mut remaining = oldremaining;
98
99                                // Check that the app is not asking for more than can
100                                // fit in the provided buffer
101                                if buffer.len() < idx {
102                                    // The buffer does not fit at all
103                                    // anymore (the app must've swapped
104                                    // buffers), end the operation
105                                    return (0, 0);
106                                } else if buffer.len() < idx + remaining {
107                                    remaining = buffer.len() - idx;
108                                }
109
110                                // Add all available and requested randomness to the app buffer.
111
112                                // 1. Slice buffer to start from current idx
113                                let buf = &buffer[idx..(idx + remaining)];
114                                // 2. Take at most as many random samples as needed to fill the buffer
115                                //    (if app.remaining is not word-sized, take an extra one).
116                                let remaining_ints = if remaining % 4 == 0 {
117                                    remaining / 4
118                                } else {
119                                    remaining / 4 + 1
120                                };
121
122                                // 3. Zip over the randomness iterator and chunks
123                                //    of up to 4 bytes from the buffer.
124                                for (inp, outs) in
125                                    randomness.take(remaining_ints).zip(buf.chunks(4))
126                                {
127                                    // 4. For each word of randomness input, update
128                                    //    the remaining and idx and add to buffer.
129                                    let inbytes = u32::to_le_bytes(inp);
130                                    outs.iter().zip(inbytes.iter()).for_each(|(out, inb)| {
131                                        out.set(*inb);
132                                        remaining -= 1;
133                                        idx += 1;
134                                    });
135                                }
136
137                                (idx, remaining)
138                            })
139                        })
140                        .unwrap_or(
141                            // If the process is no longer alive
142                            // (or this is a default AppSlice),
143                            // set the idx and remaining values of
144                            // this app to (0, 0)
145                            (0, 0),
146                        );
147
148                    // Store the updated values in the application
149                    app.idx = newidx;
150                    app.remaining = newremaining;
151
152                    if app.remaining > 0 {
153                        done = false;
154                    } else {
155                        kernel_data.schedule_upcall(0, (0, newidx, 0)).ok();
156                    }
157                }
158            });
159
160            // Check if done switched to false. If it did, then that app
161            // didn't get enough random, so there's no way there is more for
162            // other apps.
163            if !done {
164                break;
165            }
166        }
167
168        if done {
169            self.getting_randomness.set(false);
170            rng::Continue::Done
171        } else {
172            rng::Continue::More
173        }
174    }
175}
176
177impl<'a, R: Rng<'a>> SyscallDriver for RngDriver<'a, R> {
178    fn command(
179        &self,
180        command_num: usize,
181        data: usize,
182        _: usize,
183        processid: ProcessId,
184    ) -> CommandReturn {
185        match command_num {
186            // Driver existence check
187            0 => CommandReturn::success(),
188
189            // Ask for a given number of random bytes
190            1 => {
191                let mut needs_get = false;
192                let result = self
193                    .apps
194                    .enter(processid, |app, _| {
195                        app.remaining = data;
196                        app.idx = 0;
197
198                        // Assume that the process has a callback & slice
199                        // set. It might die or revoke them before the
200                        // result arrives anyways
201                        if !self.getting_randomness.get() {
202                            self.getting_randomness.set(true);
203                            needs_get = true;
204                        }
205
206                        CommandReturn::success()
207                    })
208                    .unwrap_or_else(|err| CommandReturn::failure(err.into()));
209                if needs_get {
210                    let _ = self.rng.get();
211                }
212                result
213            }
214            _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
215        }
216    }
217
218    fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
219        self.apps.enter(processid, |_, _| {})
220    }
221}
222
223pub struct Entropy32ToRandom<'a, E: Entropy32<'a>> {
224    egen: &'a E,
225    client: OptionalCell<&'a dyn rng::Client>,
226}
227
228impl<'a, E: Entropy32<'a>> Entropy32ToRandom<'a, E> {
229    pub fn new(egen: &'a E) -> Self {
230        Self {
231            egen,
232            client: OptionalCell::empty(),
233        }
234    }
235}
236
237impl<'a, E: Entropy32<'a>> Rng<'a> for Entropy32ToRandom<'a, E> {
238    fn get(&self) -> Result<(), ErrorCode> {
239        self.egen.get()
240    }
241
242    fn cancel(&self) -> Result<(), ErrorCode> {
243        self.egen.cancel()
244    }
245
246    fn set_client(&'a self, client: &'a dyn rng::Client) {
247        self.egen.set_client(self);
248        self.client.set(client);
249    }
250}
251
252impl<'a, E: Entropy32<'a>> entropy::Client32 for Entropy32ToRandom<'a, E> {
253    fn entropy_available(
254        &self,
255        entropy: &mut dyn Iterator<Item = u32>,
256        error: Result<(), ErrorCode>,
257    ) -> entropy::Continue {
258        self.client.map_or(entropy::Continue::Done, |client| {
259            if error != Ok(()) {
260                match client.randomness_available(&mut Entropy32ToRandomIter(entropy), error) {
261                    rng::Continue::More => entropy::Continue::More,
262                    rng::Continue::Done => entropy::Continue::Done,
263                }
264            } else {
265                match client.randomness_available(&mut Entropy32ToRandomIter(entropy), Ok(())) {
266                    rng::Continue::More => entropy::Continue::More,
267                    rng::Continue::Done => entropy::Continue::Done,
268                }
269            }
270        })
271    }
272}
273
274struct Entropy32ToRandomIter<'a>(&'a mut dyn Iterator<Item = u32>);
275
276impl Iterator for Entropy32ToRandomIter<'_> {
277    type Item = u32;
278
279    fn next(&mut self) -> Option<u32> {
280        self.0.next()
281    }
282}
283
284pub struct Entropy8To32<'a, E: Entropy8<'a>> {
285    egen: &'a E,
286    client: OptionalCell<&'a dyn entropy::Client32>,
287    count: Cell<usize>,
288    bytes: Cell<u32>,
289}
290
291impl<'a, E: Entropy8<'a>> Entropy8To32<'a, E> {
292    pub fn new(egen: &'a E) -> Self {
293        Self {
294            egen,
295            client: OptionalCell::empty(),
296            count: Cell::new(0),
297            bytes: Cell::new(0),
298        }
299    }
300}
301
302impl<'a, E: Entropy8<'a>> Entropy32<'a> for Entropy8To32<'a, E> {
303    fn get(&self) -> Result<(), ErrorCode> {
304        self.egen.get()
305    }
306
307    /// Cancel acquisition of random numbers.
308    ///
309    /// There are two valid return values:
310    ///   - Ok(()): an outstanding request from `get` has been cancelled,
311    ///     or there was no outstanding request. No `randomness_available`
312    ///     callback will be issued.
313    ///   - FAIL: There will be a randomness_available callback, which
314    ///     may or may not return an error code.
315    fn cancel(&self) -> Result<(), ErrorCode> {
316        self.egen.cancel()
317    }
318
319    fn set_client(&'a self, client: &'a dyn entropy::Client32) {
320        self.egen.set_client(self);
321        self.client.set(client);
322    }
323}
324
325impl<'a, E: Entropy8<'a>> entropy::Client8 for Entropy8To32<'a, E> {
326    fn entropy_available(
327        &self,
328        entropy: &mut dyn Iterator<Item = u8>,
329        error: Result<(), ErrorCode>,
330    ) -> entropy::Continue {
331        self.client.map_or(entropy::Continue::Done, |client| {
332            if error != Ok(()) {
333                client.entropy_available(&mut Entropy8To32Iter(self), error)
334            } else {
335                let mut count = self.count.get();
336                // Read in one byte at a time until we have 4;
337                // return More if we need more, else return the value
338                // of the upper randomness_available, as if it needs more
339                // we'll need more from the underlying Rng8.
340                while count < 4 {
341                    let byte = entropy.next();
342                    match byte {
343                        None => {
344                            return entropy::Continue::More;
345                        }
346                        Some(val) => {
347                            let current = self.bytes.get();
348                            let bits = val as u32;
349                            let result = current | (bits << (8 * count));
350                            count += 1;
351                            self.count.set(count);
352                            self.bytes.set(result)
353                        }
354                    }
355                }
356                let rval = client.entropy_available(&mut Entropy8To32Iter(self), Ok(()));
357                self.bytes.set(0);
358                rval
359            }
360        })
361    }
362}
363
364struct Entropy8To32Iter<'a, 'b: 'a, E: Entropy8<'b>>(&'a Entropy8To32<'b, E>);
365
366impl<'a, 'b: 'a, E: Entropy8<'b>> Iterator for Entropy8To32Iter<'a, 'b, E> {
367    type Item = u32;
368
369    fn next(&mut self) -> Option<u32> {
370        let count = self.0.count.get();
371        if count == 4 {
372            self.0.count.set(0);
373            Some(self.0.bytes.get())
374        } else {
375            None
376        }
377    }
378}
379
380pub struct Entropy32To8<'a, E: Entropy32<'a>> {
381    egen: &'a E,
382    client: OptionalCell<&'a dyn entropy::Client8>,
383    entropy: Cell<u32>,
384    bytes_consumed: Cell<usize>,
385}
386
387impl<'a, E: Entropy32<'a>> Entropy32To8<'a, E> {
388    pub fn new(egen: &'a E) -> Self {
389        Self {
390            egen,
391            client: OptionalCell::empty(),
392            entropy: Cell::new(0),
393            bytes_consumed: Cell::new(0),
394        }
395    }
396}
397
398impl<'a, E: Entropy32<'a>> Entropy8<'a> for Entropy32To8<'a, E> {
399    fn get(&self) -> Result<(), ErrorCode> {
400        self.egen.get()
401    }
402
403    /// Cancel acquisition of random numbers.
404    ///
405    /// There are two valid return values:
406    ///   - Ok(()): an outstanding request from `get` has been cancelled,
407    ///     or there was no outstanding request. No `randomness_available`
408    ///     callback will be issued.
409    ///   - FAIL: There will be a randomness_available callback, which
410    ///     may or may not return an error code.
411    fn cancel(&self) -> Result<(), ErrorCode> {
412        self.egen.cancel()
413    }
414
415    fn set_client(&'a self, client: &'a dyn entropy::Client8) {
416        self.egen.set_client(self);
417        self.client.set(client);
418    }
419}
420
421impl<'a, E: Entropy32<'a>> entropy::Client32 for Entropy32To8<'a, E> {
422    fn entropy_available(
423        &self,
424        entropy: &mut dyn Iterator<Item = u32>,
425        error: Result<(), ErrorCode>,
426    ) -> entropy::Continue {
427        self.client.map_or(entropy::Continue::Done, |client| {
428            if error != Ok(()) {
429                client.entropy_available(&mut Entropy32To8Iter::<E>(self), error)
430            } else {
431                let r = entropy.next();
432                match r {
433                    None => return entropy::Continue::More,
434                    Some(val) => {
435                        self.entropy.set(val);
436                        self.bytes_consumed.set(0);
437                    }
438                }
439                client.entropy_available(&mut Entropy32To8Iter(self), Ok(()))
440            }
441        })
442    }
443}
444
445struct Entropy32To8Iter<'a, 'b: 'a, E: Entropy32<'b>>(&'a Entropy32To8<'b, E>);
446
447impl<'a, 'b: 'a, E: Entropy32<'b>> Iterator for Entropy32To8Iter<'a, 'b, E> {
448    type Item = u8;
449
450    fn next(&mut self) -> Option<u8> {
451        let bytes_consumed = self.0.bytes_consumed.get();
452        if bytes_consumed < 4 {
453            // Pull out a byte and right shift the u32 so its
454            // least significant byte is fresh randomness.
455            let entropy = self.0.entropy.get();
456            let byte = (entropy & 0xff) as u8;
457            self.0.entropy.set(entropy >> 8);
458            self.0.bytes_consumed.set(bytes_consumed + 1);
459            Some(byte)
460        } else {
461            None
462        }
463    }
464}
465
466pub struct SynchronousRandom<'a, R: Rng<'a>> {
467    rgen: &'a R,
468    seed: Cell<u32>,
469}
470
471#[allow(dead_code)]
472impl<'a, R: Rng<'a>> SynchronousRandom<'a, R> {
473    fn new(rgen: &'a R) -> Self {
474        Self {
475            rgen,
476            seed: Cell::new(0),
477        }
478    }
479}
480
481impl<'a, R: Rng<'a>> Random<'a> for SynchronousRandom<'a, R> {
482    fn initialize(&'a self) {
483        self.rgen.set_client(self);
484        let _ = self.rgen.get();
485    }
486
487    fn reseed(&self, seed: u32) {
488        self.seed.set(seed);
489    }
490
491    // This implementation uses a linear congruential generator due to
492    // its efficiency. The parameters for the generator are those
493    // recommended in Numerical Recipes by Press, Teukolsky,
494    // Vetterling, and Flannery.
495
496    fn random(&self) -> u32 {
497        const LCG_MULTIPLIER: u32 = 1_644_525;
498        const LCG_INCREMENT: u32 = 1_013_904_223;
499        let val = self.seed.get();
500        let val = val.wrapping_mul(LCG_MULTIPLIER);
501        let val = val.wrapping_add(LCG_INCREMENT);
502        self.seed.set(val);
503        val
504    }
505}
506
507impl<'a, R: Rng<'a>> Client for SynchronousRandom<'a, R> {
508    fn randomness_available(
509        &self,
510        randomness: &mut dyn Iterator<Item = u32>,
511        _error: Result<(), ErrorCode>,
512    ) -> Continue {
513        match randomness.next() {
514            None => Continue::More,
515            Some(val) => {
516                self.seed.set(val);
517                Continue::Done
518            }
519        }
520    }
521}