blob: 00567b8e583239d3033c9158e9b06750df0b5545 [file] [log] [blame]
Pierre-Clément Tosi90cd4f12023-02-17 11:19:56 +00001// Copyright 2023, 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
Pierre-Clément Tosicb38e6d2023-06-22 10:51:00 +000015//! Functions and drivers for obtaining true entropy.
16
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000017use crate::hvc;
18use core::fmt;
19use core::mem::size_of;
20
Pierre-Clément Tosicb38e6d2023-06-22 10:51:00 +000021/// Error type for rand operations.
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000022pub enum Error {
23 /// Error during SMCCC TRNG call.
24 Trng(hvc::trng::Error),
25 /// Unsupported SMCCC TRNG version.
26 UnsupportedVersion((u16, u16)),
27}
28
29impl From<hvc::trng::Error> for Error {
30 fn from(e: hvc::trng::Error) -> Self {
31 Self::Trng(e)
32 }
33}
34
Pierre-Clément Tosicb38e6d2023-06-22 10:51:00 +000035/// Result type for rand operations.
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000036pub type Result<T> = core::result::Result<T, Error>;
37
38impl fmt::Display for Error {
39 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
40 match self {
41 Self::Trng(e) => write!(f, "SMCCC TRNG error: {e}"),
42 Self::UnsupportedVersion((x, y)) => {
43 write!(f, "Unsupported SMCCC TRNG version v{x}.{y}")
44 }
45 }
46 }
47}
48
Pierre-Clément Tosi78b68512023-06-22 09:40:16 +000049impl fmt::Debug for Error {
50 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
51 write!(f, "{self}")
52 }
53}
54
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000055/// Configure the source of entropy.
56pub fn init() -> Result<()> {
57 match hvc::trng_version()? {
58 (1, _) => Ok(()),
59 version => Err(Error::UnsupportedVersion(version)),
60 }
61}
62
63fn fill_with_entropy(s: &mut [u8]) -> Result<()> {
64 const MAX_BYTES_PER_CALL: usize = size_of::<hvc::TrngRng64Entropy>();
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000065
66 let (aligned, remainder) = s.split_at_mut(s.len() - s.len() % MAX_BYTES_PER_CALL);
67
68 for chunk in aligned.chunks_exact_mut(MAX_BYTES_PER_CALL) {
Pierre-Clément Tosicb0340c2023-03-06 11:49:39 +000069 let (r, s, t) = repeat_trng_rnd(chunk.len())?;
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000070
71 let mut words = chunk.chunks_exact_mut(size_of::<u64>());
72 words.next().unwrap().clone_from_slice(&t.to_ne_bytes());
73 words.next().unwrap().clone_from_slice(&s.to_ne_bytes());
74 words.next().unwrap().clone_from_slice(&r.to_ne_bytes());
75 }
76
77 if !remainder.is_empty() {
78 let mut entropy = [0; MAX_BYTES_PER_CALL];
Pierre-Clément Tosicb0340c2023-03-06 11:49:39 +000079 let (r, s, t) = repeat_trng_rnd(remainder.len())?;
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000080
81 let mut words = entropy.chunks_exact_mut(size_of::<u64>());
82 words.next().unwrap().clone_from_slice(&t.to_ne_bytes());
83 words.next().unwrap().clone_from_slice(&s.to_ne_bytes());
84 words.next().unwrap().clone_from_slice(&r.to_ne_bytes());
85
86 remainder.clone_from_slice(&entropy[..remainder.len()]);
87 }
88
89 Ok(())
90}
91
Pierre-Clément Tosicb0340c2023-03-06 11:49:39 +000092fn repeat_trng_rnd(n_bytes: usize) -> hvc::trng::Result<hvc::TrngRng64Entropy> {
93 let bits = usize::try_from(u8::BITS).unwrap();
94 let n_bits = (n_bytes * bits).try_into().unwrap();
95 loop {
96 match hvc::trng_rnd64(n_bits) {
97 Err(hvc::trng::Error::NoEntropy) => continue,
98 res => return res,
99 }
100 }
101}
102
Pierre-Clément Tosicb38e6d2023-06-22 10:51:00 +0000103/// Generate an array of fixed-size initialized with true-random bytes.
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +0000104pub fn random_array<const N: usize>() -> Result<[u8; N]> {
105 let mut arr = [0; N];
106 fill_with_entropy(&mut arr)?;
107 Ok(arr)
108}
109
Pierre-Clément Tosi90cd4f12023-02-17 11:19:56 +0000110#[no_mangle]
111extern "C" fn CRYPTO_sysrand_for_seed(out: *mut u8, req: usize) {
112 CRYPTO_sysrand(out, req)
113}
114
115#[no_mangle]
116extern "C" fn CRYPTO_sysrand(out: *mut u8, req: usize) {
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +0000117 // SAFETY - We need to assume that out points to valid memory of size req.
118 let s = unsafe { core::slice::from_raw_parts_mut(out, req) };
Pierre-Clément Tosi78b68512023-06-22 09:40:16 +0000119 fill_with_entropy(s).unwrap()
Pierre-Clément Tosi90cd4f12023-02-17 11:19:56 +0000120}