• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 
15 use crate::hvc;
16 use core::fmt;
17 use core::mem::size_of;
18 
19 pub enum Error {
20     /// Error during SMCCC TRNG call.
21     Trng(hvc::trng::Error),
22     /// Unsupported SMCCC TRNG version.
23     UnsupportedVersion((u16, u16)),
24 }
25 
26 impl From<hvc::trng::Error> for Error {
from(e: hvc::trng::Error) -> Self27     fn from(e: hvc::trng::Error) -> Self {
28         Self::Trng(e)
29     }
30 }
31 
32 pub type Result<T> = core::result::Result<T, Error>;
33 
34 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result35     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.
init() -> Result<()>46 pub fn init() -> Result<()> {
47     match hvc::trng_version()? {
48         (1, _) => Ok(()),
49         version => Err(Error::UnsupportedVersion(version)),
50     }
51 }
52 
fill_with_entropy(s: &mut [u8]) -> Result<()>53 fn fill_with_entropy(s: &mut [u8]) -> Result<()> {
54     const MAX_BYTES_PER_CALL: usize = size_of::<hvc::TrngRng64Entropy>();
55 
56     let (aligned, remainder) = s.split_at_mut(s.len() - s.len() % MAX_BYTES_PER_CALL);
57 
58     for chunk in aligned.chunks_exact_mut(MAX_BYTES_PER_CALL) {
59         let (r, s, t) = repeat_trng_rnd(chunk.len())?;
60 
61         let mut words = chunk.chunks_exact_mut(size_of::<u64>());
62         words.next().unwrap().clone_from_slice(&t.to_ne_bytes());
63         words.next().unwrap().clone_from_slice(&s.to_ne_bytes());
64         words.next().unwrap().clone_from_slice(&r.to_ne_bytes());
65     }
66 
67     if !remainder.is_empty() {
68         let mut entropy = [0; MAX_BYTES_PER_CALL];
69         let (r, s, t) = repeat_trng_rnd(remainder.len())?;
70 
71         let mut words = entropy.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         remainder.clone_from_slice(&entropy[..remainder.len()]);
77     }
78 
79     Ok(())
80 }
81 
repeat_trng_rnd(n_bytes: usize) -> hvc::trng::Result<hvc::TrngRng64Entropy>82 fn repeat_trng_rnd(n_bytes: usize) -> hvc::trng::Result<hvc::TrngRng64Entropy> {
83     let bits = usize::try_from(u8::BITS).unwrap();
84     let n_bits = (n_bytes * bits).try_into().unwrap();
85     loop {
86         match hvc::trng_rnd64(n_bits) {
87             Err(hvc::trng::Error::NoEntropy) => continue,
88             res => return res,
89         }
90     }
91 }
92 
random_array<const N: usize>() -> Result<[u8; N]>93 pub fn random_array<const N: usize>() -> Result<[u8; N]> {
94     let mut arr = [0; N];
95     fill_with_entropy(&mut arr)?;
96     Ok(arr)
97 }
98 
99 #[no_mangle]
CRYPTO_sysrand_for_seed(out: *mut u8, req: usize)100 extern "C" fn CRYPTO_sysrand_for_seed(out: *mut u8, req: usize) {
101     CRYPTO_sysrand(out, req)
102 }
103 
104 #[no_mangle]
CRYPTO_sysrand(out: *mut u8, req: usize)105 extern "C" fn CRYPTO_sysrand(out: *mut u8, req: usize) {
106     // SAFETY - We need to assume that out points to valid memory of size req.
107     let s = unsafe { core::slice::from_raw_parts_mut(out, req) };
108     let _ = fill_with_entropy(s);
109 }
110