From 35cd0db91336f1bae1967001f5f58864fe3b4ba8 Mon Sep 17 00:00:00 2001 From: Aaron Gallagher <_@habnab.it> Date: Fri, 29 Jul 2016 09:01:22 +0000 Subject: [PATCH 1/3] Reduce duplication in std::sys::unix::rand. There were a bunch of more-of-less the same few lines for doing a fill_bytes+transmute, and I didn't want to copy-paste it yet again. --- src/os.rs | 60 +++++++++++++++++-------------------------------------- 1 file changed, 18 insertions(+), 42 deletions(-) diff --git a/src/os.rs b/src/os.rs index fc36012b827..809e34c78e3 100644 --- a/src/os.rs +++ b/src/os.rs @@ -11,7 +11,7 @@ //! Interfaces to the operating system provided random number //! generators. -use std::io; +use std::{io, mem}; use Rng; /// A random number generator that retrieves randomness straight from @@ -40,18 +40,30 @@ impl Rng for OsRng { fn fill_bytes(&mut self, v: &mut [u8]) { self.0.fill_bytes(v) } } +fn next_u32(mut fill_buf: &mut FnMut(&mut [u8])) -> u32 { + let mut buf: [u8; 4] = [0; 4]; + fill_buf(&mut buf); + unsafe { mem::transmute::<[u8; 4], u32>(buf) } +} + +fn next_u64(mut fill_buf: &mut FnMut(&mut [u8])) -> u64 { + let mut buf: [u8; 8] = [0; 8]; + fill_buf(&mut buf); + unsafe { mem::transmute::<[u8; 8], u64>(buf) } +} + #[cfg(all(unix, not(target_os = "ios"), not(target_os = "nacl")))] mod imp { extern crate libc; + use super::{next_u32, next_u64}; use self::OsRngInner::*; use std::io; use std::fs::File; use Rng; use read::ReadRng; - use std::mem; #[cfg(all(target_os = "linux", any(target_arch = "x86_64", @@ -106,18 +118,6 @@ mod imp { } } - fn getrandom_next_u32() -> u32 { - let mut buf: [u8; 4] = [0u8; 4]; - getrandom_fill_bytes(&mut buf); - unsafe { mem::transmute::<[u8; 4], u32>(buf) } - } - - fn getrandom_next_u64() -> u64 { - let mut buf: [u8; 8] = [0u8; 8]; - getrandom_fill_bytes(&mut buf); - unsafe { mem::transmute::<[u8; 8], u64>(buf) } - } - #[cfg(all(target_os = "linux", any(target_arch = "x86_64", target_arch = "x86", @@ -202,8 +202,9 @@ mod imp { mod imp { extern crate libc; + use super::{next_u32, next_u64}; + use std::io; - use std::mem; use Rng; use self::libc::{c_int, size_t}; @@ -228,14 +229,10 @@ mod imp { impl Rng for OsRng { fn next_u32(&mut self) -> u32 { - let mut v = [0u8; 4]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } + next_u32(&mut |v| self.fill_bytes(v)) } fn next_u64(&mut self) -> u64 { - let mut v = [0u8; 8]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } + next_u64(&mut |v| self.fill_bytes(v)) } fn fill_bytes(&mut self, v: &mut [u8]) { let ret = unsafe { @@ -251,7 +248,6 @@ mod imp { #[cfg(windows)] mod imp { use std::io; - use std::mem; use std::ptr; use Rng; @@ -300,16 +296,6 @@ mod imp { } impl Rng for OsRng { - fn next_u32(&mut self) -> u32 { - let mut v = [0u8; 4]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } - } - fn next_u64(&mut self) -> u64 { - let mut v = [0u8; 8]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } - } fn fill_bytes(&mut self, v: &mut [u8]) { // CryptGenRandom takes a DWORD (u32) for the length so we need to // split up the buffer. @@ -389,16 +375,6 @@ mod imp { } impl Rng for OsRng { - fn next_u32(&mut self) -> u32 { - let mut v = [0u8; 4]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } - } - fn next_u64(&mut self) -> u64 { - let mut v = [0u8; 8]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } - } fn fill_bytes(&mut self, v: &mut [u8]) { let mut read = 0; loop { From 9dbe3d9b32b7a3cd862221b4260b44dd341e4cdd Mon Sep 17 00:00:00 2001 From: Aaron Gallagher <_@habnab.it> Date: Wed, 3 Aug 2016 20:09:14 +0000 Subject: [PATCH 2/3] Use the kernel arc4rand for FreeBSD OsRng. This means that /dev/urandom doesn't have to be opened. --- src/os.rs | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/os.rs b/src/os.rs index 809e34c78e3..f55ff4ad4de 100644 --- a/src/os.rs +++ b/src/os.rs @@ -53,7 +53,8 @@ fn next_u64(mut fill_buf: &mut FnMut(&mut [u8])) -> u64 { } #[cfg(all(unix, not(target_os = "ios"), - not(target_os = "nacl")))] + not(target_os = "nacl"), + not(target_os = "freebsd")))] mod imp { extern crate libc; @@ -245,6 +246,49 @@ mod imp { } } +#[cfg(target_os = "freebsd")] +mod imp { + extern crate libc; + + use std::{io, ptr}; + use Rng; + + use super::{next_u32, next_u64}; + + pub struct OsRng; + + impl OsRng { + pub fn new() -> io::Result { + Ok(OsRng) + } + } + + impl Rng for OsRng { + fn next_u32(&mut self) -> u32 { + next_u32(&mut |v| self.fill_bytes(v)) + } + fn next_u64(&mut self) -> u64 { + next_u64(&mut |v| self.fill_bytes(v)) + } + fn fill_bytes(&mut self, v: &mut [u8]) { + let mib = [libc::CTL_KERN, libc::KERN_ARND]; + // kern.arandom permits a maximum buffer size of 256 bytes + for s in v.chunks_mut(256) { + let mut s_len = s.len(); + let ret = unsafe { + libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint, + s.as_mut_ptr() as *mut _, &mut s_len, + ptr::null(), 0) + }; + if ret == -1 || s_len != s.len() { + panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})", + ret, s.len(), s_len); + } + } + } + } +} + #[cfg(windows)] mod imp { use std::io; From 4a2c9965e08cb0e4da264ca37061a3780acf7882 Mon Sep 17 00:00:00 2001 From: Aaron Gallagher <_@habnab.it> Date: Wed, 3 Aug 2016 23:07:45 -0700 Subject: [PATCH 3/3] Complete the refactor. I thought I did this, but I guess not. --- src/os.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/os.rs b/src/os.rs index f55ff4ad4de..4cfad6b9745 100644 --- a/src/os.rs +++ b/src/os.rs @@ -180,13 +180,13 @@ mod imp { impl Rng for OsRng { fn next_u32(&mut self) -> u32 { match self.inner { - OsGetrandomRng => getrandom_next_u32(), + OsGetrandomRng => next_u32(&mut getrandom_fill_bytes), OsReadRng(ref mut rng) => rng.next_u32(), } } fn next_u64(&mut self) -> u64 { match self.inner { - OsGetrandomRng => getrandom_next_u64(), + OsGetrandomRng => next_u64(&mut getrandom_fill_bytes), OsReadRng(ref mut rng) => rng.next_u64(), } } @@ -295,6 +295,8 @@ mod imp { use std::ptr; use Rng; + use super::{next_u32, next_u64}; + type BOOL = i32; type LPCSTR = *const i8; type DWORD = u32; @@ -340,6 +342,12 @@ mod imp { } impl Rng for OsRng { + fn next_u32(&mut self) -> u32 { + next_u32(&mut |v| self.fill_bytes(v)) + } + fn next_u64(&mut self) -> u64 { + next_u64(&mut |v| self.fill_bytes(v)) + } fn fill_bytes(&mut self, v: &mut [u8]) { // CryptGenRandom takes a DWORD (u32) for the length so we need to // split up the buffer. @@ -377,6 +385,8 @@ mod imp { use std::mem; use Rng; + use super::{next_u32, next_u64}; + pub struct OsRng(extern fn(dest: *mut libc::c_void, bytes: libc::size_t, read: *mut libc::size_t) -> libc::c_int); @@ -419,6 +429,12 @@ mod imp { } impl Rng for OsRng { + fn next_u32(&mut self) -> u32 { + next_u32(&mut |v| self.fill_bytes(v)) + } + fn next_u64(&mut self) -> u64 { + next_u64(&mut |v| self.fill_bytes(v)) + } fn fill_bytes(&mut self, v: &mut [u8]) { let mut read = 0; loop {