Skip to content
Merged
14 changes: 3 additions & 11 deletions src/dragonfly_haiku.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,16 @@

//! Implementation for DragonFly / Haiku
use super::Error;
use super::utils::use_init;
use std::fs::File;
use std::io::Read;
use std::cell::RefCell;
use std::ops::DerefMut;

thread_local!(static RNG_FILE: RefCell<Option<File>> = RefCell::new(None));

pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
RNG_FILE.with(|f| {
let mut f = f.borrow_mut();
let f: &mut Option<File> = f.deref_mut();
if let Some(f) = f {
f.read_exact(dest)
} else {
let mut rng_file = File::open("/dev/random")?;
rng_file.read_exact(dest)?;
*f = Some(rng_file);
Ok(())
}
use_init(f, || File::open("/dev/random"), |f| f.read_exact(dest))
}).map_err(|_| Error::Unknown)
}

26 changes: 10 additions & 16 deletions src/emscripten.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation for DragonFly / Haiku / Emscripten
//! Implementation for Emscripten
use super::Error;
use std::fs::File;
use std::io::Read;
use std::cell::RefCell;
use std::ops::DerefMut;
use super::utils::use_init;

thread_local!(static RNG_FILE: RefCell<Option<File>> = RefCell::new(None));

Expand All @@ -20,19 +20,13 @@ pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
// bytes. `crypto.randomBytes` documents: "To minimize threadpool
// task length variation, partition large randomBytes requests when
// doing so as part of fulfilling a client request.
for chunk in dest.chunks_mut(65536) {
RNG_FILE.with(|f| {
let mut f = f.borrow_mut();
let f: &mut Option<File> = f.deref_mut();
if let Some(f) = f {
f.read_exact(chunk)
} else {
let mut rng_file = File::open("/dev/random")?;
rng_file.read_exact(chunk)?;
*f = Some(rng_file);
Ok(())
RNG_FILE.with(|f| {
use_init(f, || File::open("/dev/random"), |f| {
for chunk in dest.chunks_mut(65536) {
f.read_exact(chunk)?;
}
}).map_err(|_| Error::Unknown)?;
}
Ok(())
Ok(())
})
}).map_err(|_| Error::Unknown)
}

5 changes: 3 additions & 2 deletions src/freebsd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
extern crate libc;

use super::Error;
use std::ptr;
use core::ptr;

pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
let mib = [libc::CTL_KERN, libc::KERN_ARND];
Expand All @@ -28,4 +28,5 @@ pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
}
}
Ok(())
}
}

1 change: 1 addition & 0 deletions src/fuchsia.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
fuchsia_cprng::cprng_draw(dest);
Ok(())
}

11 changes: 11 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@
))]
#[macro_use] extern crate std;

#[cfg(any(
target_os = "android",
target_os = "netbsd",
target_os = "solaris",
target_os = "redox",
target_os = "dragonfly",
target_os = "haiku",
target_os = "emscripten",
target_os = "linux",
))]
mod utils;
Comment thread
dhardy marked this conversation as resolved.
mod error;
pub use error::Error;

Expand Down
44 changes: 18 additions & 26 deletions src/linux_android.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,19 @@ extern crate std;
extern crate libc;

use super::Error;
use super::utils::use_init;
use std::fs::File;
use std::io;
use std::io::Read;
use std::cell::RefCell;
use std::ops::DerefMut;

enum RngSource {
GetRandom,
Device(File),
None,
}

thread_local!(
static RNG_SOURCE: RefCell<RngSource> = RefCell::new(RngSource::None);
static RNG_SOURCE: RefCell<Option<RngSource>> = RefCell::new(None);
);

fn syscall_getrandom(dest: &mut [u8]) -> Result<(), io::Error> {
Expand All @@ -39,30 +38,24 @@ fn syscall_getrandom(dest: &mut [u8]) -> Result<(), io::Error> {

pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
RNG_SOURCE.with(|f| {
let mut f = f.borrow_mut();
let f: &mut RngSource = f.deref_mut();
if let RngSource::None = f {
*f = if is_getrandom_available() {
use_init(f,
|| {
let s = if is_getrandom_available() {
RngSource::GetRandom
} else {
let mut buf = [0u8; 1];
File::open("/dev/random")
.and_then(|mut f| f.read_exact(&mut buf))
.map_err(|_| Error::Unknown)?;
let mut rng_file = File::open("/dev/urandom")
.map_err(|_| Error::Unknown)?;
RngSource::Device(rng_file)
// read one byte from "/dev/random" to ensure that
// OS RNG has initialized
File::open("/dev/random")?.read_exact(&mut [0u8; 1])?;
RngSource::Device(File::open("/dev/urandom")?)
};
Ok(s)
}, |f| {
match f {
RngSource::GetRandom => syscall_getrandom(dest),
RngSource::Device(f) => f.read_exact(dest),
}
}
if let RngSource::Device(f) = f {
f.read_exact(dest)
.map_err(|_| Error::Unknown)
} else {
syscall_getrandom(dest)
.map_err(|_| Error::Unknown)
}
})?;
Ok(())
}).map_err(|_| Error::Unknown)
})
}

fn is_getrandom_available() -> bool {
Expand All @@ -76,8 +69,7 @@ fn is_getrandom_available() -> bool {
let mut buf: [u8; 0] = [];
let available = match syscall_getrandom(&mut buf) {
Ok(()) => true,
Err(ref err) if err.raw_os_error() == Some(libc::ENOSYS) => false,
Err(_) => true,
Err(err) => err.raw_os_error() != Some(libc::ENOSYS),
};
AVAILABLE.store(available, Ordering::Relaxed);
});
Expand Down
2 changes: 0 additions & 2 deletions src/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
// except according to those terms.

//! Implementation for MacOS / iOS
extern crate libc;

use super::Error;

// TODO: check correctness
Expand Down
23 changes: 8 additions & 15 deletions src/netbsd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,21 @@
//! Implementation for NetBSD

use super::Error;
use super::utils::use_init;
use std::fs::File;
use std::io::Read;
use std::cell::RefCell;
use std::ops::DerefMut;

thread_local!(static RNG_FILE: RefCell<Option<File>> = RefCell::new(None));

pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
RNG_FILE.with(|f| {
let mut f = f.borrow_mut();
let f: &mut Option<File> = f.deref_mut();
if let Some(f) = f {
f.read_exact(dest)
} else {
// read one byte from /dev/random to ensure that RNG is bootstrapped
let mut buf = [0u8];
File::open("/dev/random")?.read_exact(&mut buf)?;

let mut rng_file = File::open("/dev/urandom")?;
rng_file.read_exact(dest)?;
*f = Some(rng_file);
Ok(())
}
use_init(f, || {
// read one byte from "/dev/random" to ensure that
// OS RNG has initialized
File::open("/dev/random")?.read_exact(&mut [0u8; 1])?;
File::open("/dev/urandom")
}, |f| f.read_exact(dest))
}).map_err(|_| Error::Unknown)
}

5 changes: 3 additions & 2 deletions src/openbsd_bitrig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
for chunk in dest.chunks_mut(256) {
let ret = unsafe {
libc::getentropy(
dest.as_mut_ptr() as *mut libc::c_void,
dest.len()
chunk.as_mut_ptr() as *mut libc::c_void,
chunk.len()
)
};
if ret == -1 {
Expand All @@ -25,3 +25,4 @@ pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
}
Ok(())
}

14 changes: 3 additions & 11 deletions src/redox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,16 @@

//! Implementation for Redox
use super::Error;
use super::utils::use_init;
use std::fs::File;
use std::io::Read;
use std::cell::RefCell;
use std::ops::DerefMut;

thread_local!(static RNG_FILE: RefCell<Option<File>> = RefCell::new(None));

pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
RNG_FILE.with(|f| {
let mut f = f.borrow_mut();
let f: &mut Option<File> = f.deref_mut();
if let Some(f) = f {
f.read_exact(dest)
} else {
let mut rng_file = File::open("rand:")?;
rng_file.read_exact(dest)?;
*f = Some(rng_file);
Ok(())
}
use_init(f, || File::open("rand:"), |f| f.read_exact(dest))
}).map_err(|_| Error::Unknown)
}

4 changes: 2 additions & 2 deletions src/sgx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use super::Error;
use core::{mem, ptr};
use core::arch::x86_64::_rdrand64_step;

//#[cfg(not(target_feature = "rdrand"))]
//compile_error!("enable rdrand target feature!");
#[cfg(not(target_feature = "rdrand"))]
compile_error!("enable rdrand target feature!");

const RETRY_LIMIT: usize = 32;

Expand Down
46 changes: 21 additions & 25 deletions src/solaris.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,10 @@ use std::ops::DerefMut;
enum RngSource {
GetRandom,
Device(File),
None,
}

thread_local!(
static RNG_SOURCE: RefCell<RngSource> = RefCell::new(RngSource::None);
static RNG_SOURCE: RefCell<Option<RngSource>> = RefCell::new(None);
);

fn syscall_getrandom(dest: &mut [u8]) -> Result<(), io::Error> {
Expand All @@ -55,31 +54,28 @@ fn syscall_getrandom(dest: &mut [u8]) -> Result<(), io::Error> {
}

pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
// The documentation says 1024 is the maximum for getrandom,
// but 1040 for /dev/random.
for chunk in dest.chunks_mut(1024) {
RNG_SOURCE.with(|f| {
let mut f = f.borrow_mut();
let f: &mut RngSource = f.deref_mut();
if let RngSource::None = f {
*f = if is_getrandom_available() {
RngSource::GetRandom
} else {
let mut rng_file = File::open("/dev/random")
.map_err(|_| Error::Unknown)?;
RngSource::Device(rng_file)
}
}
if let RngSource::Device(f) = f {
f.read_exact(chunk)
.map_err(|_| Error::Unknown)
// The documentation says 1024 is the maximum for getrandom
// and 1040 for /dev/random.
RNG_SOURCE.with(|f| {
use_init(f,
|| {
let s = if is_getrandom_available() {
RngSource::GetRandom
} else {
syscall_getrandom(chunk)
.map_err(|_| Error::Unknown)
RngSource::Device(File::open("/dev/random")?)
};
Ok(s)
}, |f| {
match f {
RngSource::GetRandom => for chunk in dest.chunks_mut(1024) {
syscall_getrandom(chunk)
},
RngSource::Device(f) => for chunk in dest.chunks_mut(1040) {
f.read_exact(dest)
},
}
})?;
}
Ok(())
})
}).map_err(|_| Error::Unknown)
}

fn is_getrandom_available() -> bool {
Expand Down
21 changes: 21 additions & 0 deletions src/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use std::cell::RefCell;
use std::ops::DerefMut;
use std::{io, hint};

pub(crate) fn use_init<T, F, U>(f: &RefCell<Option<T>>, init_f: F, mut use_f: U)
-> io::Result<()>
where F: FnOnce() -> io::Result<T>, U: FnMut(&mut T) -> io::Result<()>
{
let mut f = f.borrow_mut();
let f: &mut Option<T> = f.deref_mut();
match f {
None => *f = Some(init_f()?),
_ => (),
}

match f {
Some(f) => use_f(f),
None => unsafe { hint::unreachable_unchecked() },
Comment thread
newpavlov marked this conversation as resolved.
Outdated
}
}