blob: 6b8d7e02096c6d0d2f6b90bd56123a09d64da219 [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 Tosi628c4382023-06-30 18:15:37 +000017use crate::hvc::{self, TrngRng64Entropy};
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000018use core::fmt;
19use core::mem::size_of;
Pierre-Clément Tosi62ffc0d2023-06-30 09:31:56 +000020use smccc::{self, Hvc};
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000021
Pierre-Clément Tosicb38e6d2023-06-22 10:51:00 +000022/// Error type for rand operations.
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000023pub enum Error {
Pierre-Clément Tosi62ffc0d2023-06-30 09:31:56 +000024 /// No source of entropy found.
25 NoEntropySource,
26 /// Error during architectural SMCCC call.
27 Smccc(smccc::arch::Error),
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000028 /// Error during SMCCC TRNG call.
29 Trng(hvc::trng::Error),
Pierre-Clément Tosi62ffc0d2023-06-30 09:31:56 +000030 /// Unsupported SMCCC version.
31 UnsupportedSmcccVersion(smccc::arch::Version),
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000032 /// Unsupported SMCCC TRNG version.
Pierre-Clément Tosi628c4382023-06-30 18:15:37 +000033 UnsupportedTrngVersion(hvc::trng::Version),
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000034}
35
Pierre-Clément Tosi62ffc0d2023-06-30 09:31:56 +000036impl From<smccc::arch::Error> for Error {
37 fn from(e: smccc::arch::Error) -> Self {
38 Self::Smccc(e)
39 }
40}
41
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000042impl From<hvc::trng::Error> for Error {
43 fn from(e: hvc::trng::Error) -> Self {
44 Self::Trng(e)
45 }
46}
47
Pierre-Clément Tosicb38e6d2023-06-22 10:51:00 +000048/// Result type for rand operations.
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000049pub type Result<T> = core::result::Result<T, Error>;
50
51impl fmt::Display for Error {
52 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
53 match self {
Pierre-Clément Tosi62ffc0d2023-06-30 09:31:56 +000054 Self::NoEntropySource => write!(f, "No source of entropy available"),
55 Self::Smccc(e) => write!(f, "Architectural SMCCC error: {e}"),
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000056 Self::Trng(e) => write!(f, "SMCCC TRNG error: {e}"),
Pierre-Clément Tosi62ffc0d2023-06-30 09:31:56 +000057 Self::UnsupportedSmcccVersion(v) => write!(f, "Unsupported SMCCC version {v}"),
Pierre-Clément Tosi628c4382023-06-30 18:15:37 +000058 Self::UnsupportedTrngVersion(v) => write!(f, "Unsupported SMCCC TRNG version {v}"),
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000059 }
60 }
61}
62
Pierre-Clément Tosi78b68512023-06-22 09:40:16 +000063impl fmt::Debug for Error {
64 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65 write!(f, "{self}")
66 }
67}
68
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000069/// Configure the source of entropy.
Pierre-Clément Tosi62ffc0d2023-06-30 09:31:56 +000070pub(crate) fn init() -> Result<()> {
71 // SMCCC TRNG requires SMCCC v1.1.
72 match smccc::arch::version::<Hvc>()? {
73 smccc::arch::Version { major: 1, minor } if minor >= 1 => (),
74 version => return Err(Error::UnsupportedSmcccVersion(version)),
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000075 }
Pierre-Clément Tosi62ffc0d2023-06-30 09:31:56 +000076
77 // TRNG_RND requires SMCCC TRNG v1.0.
78 match hvc::trng_version()? {
Pierre-Clément Tosi628c4382023-06-30 18:15:37 +000079 hvc::trng::Version { major: 1, minor: _ } => (),
80 version => return Err(Error::UnsupportedTrngVersion(version)),
Pierre-Clément Tosi62ffc0d2023-06-30 09:31:56 +000081 }
82
83 // TRNG_RND64 doesn't define any special capabilities so ignore the successful result.
84 let _ = hvc::trng_features(hvc::ARM_SMCCC_TRNG_RND64).map_err(|e| {
85 if e == hvc::trng::Error::NotSupported {
86 // SMCCC TRNG is currently our only source of entropy.
87 Error::NoEntropySource
88 } else {
89 e.into()
90 }
91 })?;
92
93 Ok(())
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000094}
95
Pierre-Clément Tosi62ffc0d2023-06-30 09:31:56 +000096/// Fills a slice of bytes with true entropy.
97pub fn fill_with_entropy(s: &mut [u8]) -> Result<()> {
Pierre-Clément Tosi628c4382023-06-30 18:15:37 +000098 const MAX_BYTES_PER_CALL: usize = size_of::<TrngRng64Entropy>();
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +000099
100 let (aligned, remainder) = s.split_at_mut(s.len() - s.len() % MAX_BYTES_PER_CALL);
101
102 for chunk in aligned.chunks_exact_mut(MAX_BYTES_PER_CALL) {
Pierre-Clément Tosicb0340c2023-03-06 11:49:39 +0000103 let (r, s, t) = repeat_trng_rnd(chunk.len())?;
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +0000104
105 let mut words = chunk.chunks_exact_mut(size_of::<u64>());
106 words.next().unwrap().clone_from_slice(&t.to_ne_bytes());
107 words.next().unwrap().clone_from_slice(&s.to_ne_bytes());
108 words.next().unwrap().clone_from_slice(&r.to_ne_bytes());
109 }
110
111 if !remainder.is_empty() {
112 let mut entropy = [0; MAX_BYTES_PER_CALL];
Pierre-Clément Tosicb0340c2023-03-06 11:49:39 +0000113 let (r, s, t) = repeat_trng_rnd(remainder.len())?;
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +0000114
115 let mut words = entropy.chunks_exact_mut(size_of::<u64>());
116 words.next().unwrap().clone_from_slice(&t.to_ne_bytes());
117 words.next().unwrap().clone_from_slice(&s.to_ne_bytes());
118 words.next().unwrap().clone_from_slice(&r.to_ne_bytes());
119
120 remainder.clone_from_slice(&entropy[..remainder.len()]);
121 }
122
123 Ok(())
124}
125
Pierre-Clément Tosi628c4382023-06-30 18:15:37 +0000126fn repeat_trng_rnd(n_bytes: usize) -> Result<TrngRng64Entropy> {
Pierre-Clément Tosicb0340c2023-03-06 11:49:39 +0000127 let bits = usize::try_from(u8::BITS).unwrap();
128 let n_bits = (n_bytes * bits).try_into().unwrap();
129 loop {
130 match hvc::trng_rnd64(n_bits) {
Pierre-Clément Tosi628c4382023-06-30 18:15:37 +0000131 Ok(entropy) => return Ok(entropy),
132 Err(hvc::trng::Error::NoEntropy) => (),
133 Err(e) => return Err(e.into()),
Pierre-Clément Tosicb0340c2023-03-06 11:49:39 +0000134 }
135 }
136}
137
Pierre-Clément Tosicb38e6d2023-06-22 10:51:00 +0000138/// Generate an array of fixed-size initialized with true-random bytes.
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +0000139pub fn random_array<const N: usize>() -> Result<[u8; N]> {
140 let mut arr = [0; N];
141 fill_with_entropy(&mut arr)?;
142 Ok(arr)
143}
144
Pierre-Clément Tosi90cd4f12023-02-17 11:19:56 +0000145#[no_mangle]
146extern "C" fn CRYPTO_sysrand_for_seed(out: *mut u8, req: usize) {
147 CRYPTO_sysrand(out, req)
148}
149
150#[no_mangle]
151extern "C" fn CRYPTO_sysrand(out: *mut u8, req: usize) {
Andrew Walbranc06e7342023-07-05 14:00:51 +0000152 // SAFETY: We need to assume that out points to valid memory of size req.
Pierre-Clément Tosia59103d2023-02-02 14:46:55 +0000153 let s = unsafe { core::slice::from_raw_parts_mut(out, req) };
Pierre-Clément Tosi78b68512023-06-22 09:40:16 +0000154 fill_with_entropy(s).unwrap()
Pierre-Clément Tosi90cd4f12023-02-17 11:19:56 +0000155}