blob: a53cac6842dd327330dad8211bc50e4c6b785b7b [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 Tosia59103d2023-02-02 14:46:55 +000015use crate::hvc;
16use core::fmt;
17use core::mem::size_of;
18
19pub enum Error {
20 /// Error during SMCCC TRNG call.
21 Trng(hvc::trng::Error),
22 /// Unsupported SMCCC TRNG version.
23 UnsupportedVersion((u16, u16)),
24}
25
26impl From<hvc::trng::Error> for Error {
27 fn from(e: hvc::trng::Error) -> Self {
28 Self::Trng(e)
29 }
30}
31
32pub type Result<T> = core::result::Result<T, Error>;
33
34impl fmt::Display for Error {
35 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
36 match self {
37 Self::Trng(e) => write!(f, "SMCCC TRNG error: {e}"),
38 Self::UnsupportedVersion((x, y)) => {
39 write!(f, "Unsupported SMCCC TRNG version v{x}.{y}")
40 }
41 }
42 }
43}
44
45/// Configure the source of entropy.
46pub fn init() -> Result<()> {
47 match hvc::trng_version()? {
48 (1, _) => Ok(()),
49 version => Err(Error::UnsupportedVersion(version)),
50 }
51}
52
53fn fill_with_entropy(s: &mut [u8]) -> Result<()> {
54 const MAX_BYTES_PER_CALL: usize = size_of::<hvc::TrngRng64Entropy>();
55 let bits = usize::try_from(u8::BITS).unwrap();
56
57 let (aligned, remainder) = s.split_at_mut(s.len() - s.len() % MAX_BYTES_PER_CALL);
58
59 for chunk in aligned.chunks_exact_mut(MAX_BYTES_PER_CALL) {
60 let (r, s, t) = hvc::trng_rnd64((chunk.len() * bits).try_into().unwrap())?;
61
62 let mut words = chunk.chunks_exact_mut(size_of::<u64>());
63 words.next().unwrap().clone_from_slice(&t.to_ne_bytes());
64 words.next().unwrap().clone_from_slice(&s.to_ne_bytes());
65 words.next().unwrap().clone_from_slice(&r.to_ne_bytes());
66 }
67
68 if !remainder.is_empty() {
69 let mut entropy = [0; MAX_BYTES_PER_CALL];
70 let (r, s, t) = hvc::trng_rnd64((remainder.len() * bits).try_into().unwrap())?;
71
72 let mut words = entropy.chunks_exact_mut(size_of::<u64>());
73 words.next().unwrap().clone_from_slice(&t.to_ne_bytes());
74 words.next().unwrap().clone_from_slice(&s.to_ne_bytes());
75 words.next().unwrap().clone_from_slice(&r.to_ne_bytes());
76
77 remainder.clone_from_slice(&entropy[..remainder.len()]);
78 }
79
80 Ok(())
81}
82
83pub fn random_array<const N: usize>() -> Result<[u8; N]> {
84 let mut arr = [0; N];
85 fill_with_entropy(&mut arr)?;
86 Ok(arr)
87}
88
Pierre-Clément Tosi90cd4f12023-02-17 11:19:56 +000089#[no_mangle]
90extern "C" fn CRYPTO_sysrand_for_seed(out: *mut u8, req: usize) {
91 CRYPTO_sysrand(out, req)
92}
93
94#[no_mangle]
95extern "C" fn CRYPTO_sysrand(out: *mut u8, req: usize) {
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000096 // SAFETY - We need to assume that out points to valid memory of size req.
97 let s = unsafe { core::slice::from_raw_parts_mut(out, req) };
98 let _ = fill_with_entropy(s);
Pierre-Clément Tosi90cd4f12023-02-17 11:19:56 +000099}