Skip to content

Commit 47bf29d

Browse files
authored
Merge pull request #112 from habnabit/freebsd-kernel-osrng
Use arc4rand(9) on FreeBSD
2 parents f245370 + 4a2c996 commit 47bf29d

File tree

1 file changed

+73
-37
lines changed

1 file changed

+73
-37
lines changed

src/os.rs

Lines changed: 73 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
//! Interfaces to the operating system provided random number
1212
//! generators.
1313
14-
use std::io;
14+
use std::{io, mem};
1515
use Rng;
1616

1717
/// A random number generator that retrieves randomness straight from
@@ -40,18 +40,31 @@ impl Rng for OsRng {
4040
fn fill_bytes(&mut self, v: &mut [u8]) { self.0.fill_bytes(v) }
4141
}
4242

43+
fn next_u32(mut fill_buf: &mut FnMut(&mut [u8])) -> u32 {
44+
let mut buf: [u8; 4] = [0; 4];
45+
fill_buf(&mut buf);
46+
unsafe { mem::transmute::<[u8; 4], u32>(buf) }
47+
}
48+
49+
fn next_u64(mut fill_buf: &mut FnMut(&mut [u8])) -> u64 {
50+
let mut buf: [u8; 8] = [0; 8];
51+
fill_buf(&mut buf);
52+
unsafe { mem::transmute::<[u8; 8], u64>(buf) }
53+
}
54+
4355
#[cfg(all(unix, not(target_os = "ios"),
44-
not(target_os = "nacl")))]
56+
not(target_os = "nacl"),
57+
not(target_os = "freebsd")))]
4558
mod imp {
4659
extern crate libc;
4760

61+
use super::{next_u32, next_u64};
4862
use self::OsRngInner::*;
4963

5064
use std::io;
5165
use std::fs::File;
5266
use Rng;
5367
use read::ReadRng;
54-
use std::mem;
5568

5669
#[cfg(all(target_os = "linux",
5770
any(target_arch = "x86_64",
@@ -106,18 +119,6 @@ mod imp {
106119
}
107120
}
108121

109-
fn getrandom_next_u32() -> u32 {
110-
let mut buf: [u8; 4] = [0u8; 4];
111-
getrandom_fill_bytes(&mut buf);
112-
unsafe { mem::transmute::<[u8; 4], u32>(buf) }
113-
}
114-
115-
fn getrandom_next_u64() -> u64 {
116-
let mut buf: [u8; 8] = [0u8; 8];
117-
getrandom_fill_bytes(&mut buf);
118-
unsafe { mem::transmute::<[u8; 8], u64>(buf) }
119-
}
120-
121122
#[cfg(all(target_os = "linux",
122123
any(target_arch = "x86_64",
123124
target_arch = "x86",
@@ -179,13 +180,13 @@ mod imp {
179180
impl Rng for OsRng {
180181
fn next_u32(&mut self) -> u32 {
181182
match self.inner {
182-
OsGetrandomRng => getrandom_next_u32(),
183+
OsGetrandomRng => next_u32(&mut getrandom_fill_bytes),
183184
OsReadRng(ref mut rng) => rng.next_u32(),
184185
}
185186
}
186187
fn next_u64(&mut self) -> u64 {
187188
match self.inner {
188-
OsGetrandomRng => getrandom_next_u64(),
189+
OsGetrandomRng => next_u64(&mut getrandom_fill_bytes),
189190
OsReadRng(ref mut rng) => rng.next_u64(),
190191
}
191192
}
@@ -202,8 +203,9 @@ mod imp {
202203
mod imp {
203204
extern crate libc;
204205

206+
use super::{next_u32, next_u64};
207+
205208
use std::io;
206-
use std::mem;
207209
use Rng;
208210
use self::libc::{c_int, size_t};
209211

@@ -228,14 +230,10 @@ mod imp {
228230

229231
impl Rng for OsRng {
230232
fn next_u32(&mut self) -> u32 {
231-
let mut v = [0u8; 4];
232-
self.fill_bytes(&mut v);
233-
unsafe { mem::transmute(v) }
233+
next_u32(&mut |v| self.fill_bytes(v))
234234
}
235235
fn next_u64(&mut self) -> u64 {
236-
let mut v = [0u8; 8];
237-
self.fill_bytes(&mut v);
238-
unsafe { mem::transmute(v) }
236+
next_u64(&mut |v| self.fill_bytes(v))
239237
}
240238
fn fill_bytes(&mut self, v: &mut [u8]) {
241239
let ret = unsafe {
@@ -248,13 +246,57 @@ mod imp {
248246
}
249247
}
250248

249+
#[cfg(target_os = "freebsd")]
250+
mod imp {
251+
extern crate libc;
252+
253+
use std::{io, ptr};
254+
use Rng;
255+
256+
use super::{next_u32, next_u64};
257+
258+
pub struct OsRng;
259+
260+
impl OsRng {
261+
pub fn new() -> io::Result<OsRng> {
262+
Ok(OsRng)
263+
}
264+
}
265+
266+
impl Rng for OsRng {
267+
fn next_u32(&mut self) -> u32 {
268+
next_u32(&mut |v| self.fill_bytes(v))
269+
}
270+
fn next_u64(&mut self) -> u64 {
271+
next_u64(&mut |v| self.fill_bytes(v))
272+
}
273+
fn fill_bytes(&mut self, v: &mut [u8]) {
274+
let mib = [libc::CTL_KERN, libc::KERN_ARND];
275+
// kern.arandom permits a maximum buffer size of 256 bytes
276+
for s in v.chunks_mut(256) {
277+
let mut s_len = s.len();
278+
let ret = unsafe {
279+
libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
280+
s.as_mut_ptr() as *mut _, &mut s_len,
281+
ptr::null(), 0)
282+
};
283+
if ret == -1 || s_len != s.len() {
284+
panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
285+
ret, s.len(), s_len);
286+
}
287+
}
288+
}
289+
}
290+
}
291+
251292
#[cfg(windows)]
252293
mod imp {
253294
use std::io;
254-
use std::mem;
255295
use std::ptr;
256296
use Rng;
257297

298+
use super::{next_u32, next_u64};
299+
258300
type BOOL = i32;
259301
type LPCSTR = *const i8;
260302
type DWORD = u32;
@@ -301,14 +343,10 @@ mod imp {
301343

302344
impl Rng for OsRng {
303345
fn next_u32(&mut self) -> u32 {
304-
let mut v = [0u8; 4];
305-
self.fill_bytes(&mut v);
306-
unsafe { mem::transmute(v) }
346+
next_u32(&mut |v| self.fill_bytes(v))
307347
}
308348
fn next_u64(&mut self) -> u64 {
309-
let mut v = [0u8; 8];
310-
self.fill_bytes(&mut v);
311-
unsafe { mem::transmute(v) }
349+
next_u64(&mut |v| self.fill_bytes(v))
312350
}
313351
fn fill_bytes(&mut self, v: &mut [u8]) {
314352
// CryptGenRandom takes a DWORD (u32) for the length so we need to
@@ -347,6 +385,8 @@ mod imp {
347385
use std::mem;
348386
use Rng;
349387

388+
use super::{next_u32, next_u64};
389+
350390
pub struct OsRng(extern fn(dest: *mut libc::c_void,
351391
bytes: libc::size_t,
352392
read: *mut libc::size_t) -> libc::c_int);
@@ -390,14 +430,10 @@ mod imp {
390430

391431
impl Rng for OsRng {
392432
fn next_u32(&mut self) -> u32 {
393-
let mut v = [0u8; 4];
394-
self.fill_bytes(&mut v);
395-
unsafe { mem::transmute(v) }
433+
next_u32(&mut |v| self.fill_bytes(v))
396434
}
397435
fn next_u64(&mut self) -> u64 {
398-
let mut v = [0u8; 8];
399-
self.fill_bytes(&mut v);
400-
unsafe { mem::transmute(v) }
436+
next_u64(&mut |v| self.fill_bytes(v))
401437
}
402438
fn fill_bytes(&mut self, v: &mut [u8]) {
403439
let mut read = 0;

0 commit comments

Comments
 (0)