From e3cfc2a1e639aca3b7a6890033851fe0190ef9b8 Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Wed, 31 Jul 2019 17:48:22 -0400 Subject: [PATCH] Add RNG for Fortanix SGX Currently, ring doesn't provide a random number generator for SGX at all. This is probably by accident, but is, in fact, the correct behavior. Due to distrust of the OS, SGX enclave applications need a source of randomness that is not forgable by the OS. This pretty much leaves only the RDRAND instruction. Fortunately, Rust provides an intrinsic for this instruction. --- src/rand.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/rand.rs b/src/rand.rs index cb24defd7c..9512835dc6 100644 --- a/src/rand.rs +++ b/src/rand.rs @@ -193,6 +193,9 @@ use self::darwin::fill as fill_impl; #[cfg(any(target_os = "fuchsia"))] use self::fuchsia::fill as fill_impl; +#[cfg(any(target_env = "sgx"))] +use self::sgx::fill as fill_impl; + #[cfg(any(target_os = "android", target_os = "linux"))] mod sysrand_chunk { use crate::{c, error}; @@ -432,3 +435,34 @@ mod fuchsia { fn zx_cprng_draw(buffer: *mut u8, length: usize); } } + +#[cfg(any(target_env = "sgx"))] +mod sgx { + use core::arch::x86_64::_rdrand64_step; + use crate::error; + + #[inline] + fn rdrand() -> Result { + // See https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide + // Section 5.2.1 + for _ in 0..10 { + let mut r = 0; + if unsafe { _rdrand64_step(&mut r) } == 1 { + return Ok(r); + } + } + + Err(error::Unspecified) + } + + pub fn fill(mut dest: &mut [u8]) -> Result<(), error::Unspecified> { + while dest.len() > 0 { + let rand = rdrand()?.to_ne_bytes(); + let len = core::cmp::min(dest.len(), rand.len()); + dest[..len].copy_from_slice(&rand[..len]); + dest = &mut dest[len..]; + } + + Ok(()) + } +}