Skip to content

Commit 24e7f8f

Browse files
authored
Merge pull request #6 from newpavlov/init
Crate implementation
2 parents c9440a2 + af5035f commit 24e7f8f

22 files changed

+827
-4
lines changed

Cargo.toml

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,23 @@
11
[package]
22
name = "getrandom"
3-
version = "0.0.0"
3+
version = "0.1.0"
44
authors = ["The Rand Project Developers"]
5-
license = "MIT/Apache-2.0"
6-
edition = "2015"
5+
license = "MIT OR Apache-2.0"
76
description = "A small cross-platform library to securely get random data (entropy)"
87

9-
[dependencies]
8+
[badges]
9+
travis-ci = { repository = "rust-random/getrandom" }
10+
appveyor = { repository = "rust-random/getrandom" }
11+
12+
[target.'cfg(unix)'.dependencies]
13+
libc = "0.2"
14+
15+
[target.'cfg(windows)'.dependencies]
16+
winapi = { version = "0.3", features = ["minwindef", "ntsecapi", "winnt"] }
17+
18+
[target.'cfg(fuchsia)'.dependencies]
19+
fuchsia-cprng = "0.1"
20+
21+
[target.wasm32-unknown-unknown.dependencies]
22+
wasm-bindgen = { version = "0.2.12", optional = true }
23+
stdweb = { version = "0.4", optional = true }

benches/mod.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#![feature(test)]
2+
extern crate test;
3+
extern crate getrandom;
4+
5+
#[bench]
6+
fn bench_64(b: &mut test::Bencher) {
7+
let mut buf = [0u8; 64];
8+
b.iter(|| {
9+
getrandom::getrandom(&mut buf[..]).unwrap();
10+
test::black_box(&buf);
11+
});
12+
b.bytes = buf.len() as u64;
13+
}
14+
15+
#[bench]
16+
fn bench_65536(b: &mut test::Bencher) {
17+
let mut buf = [0u8; 65536];
18+
b.iter(|| {
19+
getrandom::getrandom(&mut buf[..]).unwrap();
20+
test::black_box(&buf);
21+
});
22+
b.bytes = buf.len() as u64;
23+
}
24+

src/cloudabi.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2018 Developers of the Rand project.
2+
//
3+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4+
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5+
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6+
// option. This file may not be copied, modified, or distributed
7+
// except according to those terms.
8+
use error::Error;
9+
10+
extern "C" {
11+
fn cloudabi_sys_random_get(buf: *mut u8, len: usize) -> u16;
12+
}
13+
14+
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
15+
let errno = unsafe { cloudabi_sys_random_get(dest.as_ptr(), dest.len()) };
16+
if errno == 0 {
17+
Ok(())
18+
} else {
19+
Err(Error(unsafe {
20+
NonZeroU32::new_unchecked(errno as u32)
21+
}))
22+
}
23+
}

src/dragonfly_haiku.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2018 Developers of the Rand project.
2+
//
3+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4+
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5+
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6+
// option. This file may not be copied, modified, or distributed
7+
// except according to those terms.
8+
9+
//! Implementation for DragonFly / Haiku
10+
use super::Error;
11+
use super::utils::use_init;
12+
use std::fs::File;
13+
use std::io::Read;
14+
use std::cell::RefCell;
15+
16+
thread_local!(static RNG_FILE: RefCell<Option<File>> = RefCell::new(None));
17+
18+
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
19+
RNG_FILE.with(|f| {
20+
use_init(f,
21+
|| File::open("/dev/random").map_err(From::from),
22+
|f| f.read_exact(dest).map_err(From::from),
23+
)
24+
})
25+
}

src/dummy.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2018 Developers of the Rand project.
2+
//
3+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4+
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5+
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6+
// option. This file may not be copied, modified, or distributed
7+
// except according to those terms.
8+
9+
//! A dummy implementation for unsupported targets which always returns
10+
//! `Err(UNAVAILABLE_ERROR)`
11+
use super::UNAVAILABLE_ERROR;
12+
13+
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
14+
Err(UNAVAILABLE_ERROR)
15+
}

src/emscripten.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2018 Developers of the Rand project.
2+
//
3+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4+
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5+
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6+
// option. This file may not be copied, modified, or distributed
7+
// except according to those terms.
8+
9+
//! Implementation for Emscripten
10+
use super::Error;
11+
use std::fs::File;
12+
use std::io::Read;
13+
use std::cell::RefCell;
14+
use super::utils::use_init;
15+
16+
thread_local!(static RNG_FILE: RefCell<Option<File>> = RefCell::new(None));
17+
18+
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
19+
// `Crypto.getRandomValues` documents `dest` should be at most 65536
20+
// bytes. `crypto.randomBytes` documents: "To minimize threadpool
21+
// task length variation, partition large randomBytes requests when
22+
// doing so as part of fulfilling a client request.
23+
RNG_FILE.with(|f| {
24+
use_init(f, || File::open("/dev/random").map_err(From::from), |f| {
25+
for chunk in dest.chunks_mut(65536) {
26+
f.read_exact(chunk)?;
27+
}
28+
Ok(())
29+
})
30+
})
31+
}

src/error.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Copyright 2018 Developers of the Rand project.
2+
//
3+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4+
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5+
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6+
// option. This file may not be copied, modified, or distributed
7+
// except according to those terms.
8+
9+
use core::num::NonZeroU32;
10+
use core::convert::From;
11+
use core::fmt;
12+
#[cfg(not(target_env = "sgx"))]
13+
use std::{io, error};
14+
15+
pub const UNKNOWN_ERROR: Error = Error(unsafe {
16+
NonZeroU32::new_unchecked(0x756e6b6e) // "unkn"
17+
});
18+
19+
pub const UNAVAILABLE_ERROR: Error = Error(unsafe {
20+
NonZeroU32::new_unchecked(0x4e416e61) // "NAna"
21+
});
22+
23+
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
24+
pub struct Error(NonZeroU32);
25+
26+
impl Error {
27+
pub fn code(&self) -> NonZeroU32 {
28+
self.0
29+
}
30+
}
31+
32+
impl fmt::Display for Error {
33+
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
34+
match *self {
35+
UNKNOWN_ERROR => write!(f, "Getrandom Error: unknown"),
36+
UNAVAILABLE_ERROR => write!(f, "Getrandom Error: unavailable"),
37+
code => write!(f, "Getrandom Error: {}", code.0.get()),
38+
}
39+
}
40+
}
41+
42+
#[cfg(not(target_env = "sgx"))]
43+
impl From<io::Error> for Error {
44+
fn from(err: io::Error) -> Self {
45+
err.raw_os_error()
46+
.and_then(|code| NonZeroU32::new(code as u32))
47+
.map(|code| Error(code))
48+
// in practice this should never happen
49+
.unwrap_or(UNKNOWN_ERROR)
50+
}
51+
}
52+
53+
#[cfg(not(target_env = "sgx"))]
54+
impl Into<io::Error> for Error {
55+
fn into(self) -> io::Error {
56+
match self {
57+
UNKNOWN_ERROR => io::Error::new(io::ErrorKind::Other,
58+
"getrandom error: unknown"),
59+
UNAVAILABLE_ERROR => io::Error::new(io::ErrorKind::Other,
60+
"getrandom error: entropy source is unavailable"),
61+
code => io::Error::from_raw_os_error(code.0.get() as i32),
62+
}
63+
}
64+
}
65+
66+
#[cfg(not(target_env = "sgx"))]
67+
impl error::Error for Error { }

src/freebsd.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2018 Developers of the Rand project.
2+
//
3+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4+
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5+
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6+
// option. This file may not be copied, modified, or distributed
7+
// except according to those terms.
8+
9+
//! Implementation for FreeBSD
10+
extern crate libc;
11+
12+
use super::Error;
13+
use core::ptr;
14+
use std::io;
15+
16+
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
17+
let mib = [libc::CTL_KERN, libc::KERN_ARND];
18+
// kern.arandom permits a maximum buffer size of 256 bytes
19+
for chunk in dest.chunks_mut(256) {
20+
let mut len = chunk.len();
21+
let ret = unsafe {
22+
libc::sysctl(
23+
mib.as_ptr(), mib.len() as libc::c_uint,
24+
chunk.as_mut_ptr() as *mut _, &mut len, ptr::null(), 0,
25+
)
26+
};
27+
if ret == -1 || len != chunk.len() {
28+
return Err(io::Error::last_os_error().into());
29+
}
30+
}
31+
Ok(())
32+
}

src/fuchsia.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2018 Developers of the Rand project.
2+
//
3+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4+
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5+
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6+
// option. This file may not be copied, modified, or distributed
7+
// except according to those terms.
8+
9+
//! Implementation for Fuchsia Zircon
10+
extern crate fuchsia_cprng;
11+
12+
use super::Error;
13+
14+
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
15+
fuchsia_cprng::cprng_draw(dest);
16+
Ok(())
17+
}

src/lib.rs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,98 @@
55
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
66
// option. This file may not be copied, modified, or distributed
77
// except according to those terms.
8+
#![no_std]
9+
10+
#[cfg(not(target_env = "sgx"))]
11+
#[macro_use] extern crate std;
12+
13+
#[cfg(any(
14+
target_os = "android",
15+
target_os = "netbsd",
16+
target_os = "solaris",
17+
target_os = "redox",
18+
target_os = "dragonfly",
19+
target_os = "haiku",
20+
target_os = "emscripten",
21+
target_os = "linux",
22+
))]
23+
mod utils;
24+
mod error;
25+
pub use error::{Error, UNKNOWN_ERROR, UNAVAILABLE_ERROR};
26+
27+
macro_rules! mod_use {
28+
($cond:meta, $module:ident) => {
29+
#[$cond]
30+
mod $module;
31+
#[$cond]
32+
pub use $module::getrandom;
33+
}
34+
}
35+
36+
mod_use!(cfg(target_os = "android"), linux_android);
37+
mod_use!(cfg(target_os = "bitrig"), openbsd_bitrig);
38+
mod_use!(cfg(target_os = "cloudabi"), cloudabi);
39+
mod_use!(cfg(target_os = "dragonfly"), dragonfly_haiku);
40+
mod_use!(cfg(target_os = "emscripten"), emscripten);
41+
mod_use!(cfg(target_os = "freebsd"), freebsd);
42+
mod_use!(cfg(target_os = "fuchsia"), fuchsia);
43+
mod_use!(cfg(target_os = "haiku"), dragonfly_haiku);
44+
mod_use!(cfg(target_os = "ios"), macos);
45+
mod_use!(cfg(target_os = "linux"), linux_android);
46+
mod_use!(cfg(target_os = "macos"), macos);
47+
mod_use!(cfg(target_os = "netbsd"), netbsd);
48+
mod_use!(cfg(target_os = "openbsd"), openbsd_bitrig);
49+
mod_use!(cfg(target_os = "redox"), redox);
50+
mod_use!(cfg(target_os = "solaris"), solaris);
51+
mod_use!(cfg(windows), windows);
52+
mod_use!(cfg(target_env = "sgx"), sgx);
53+
54+
mod_use!(
55+
cfg(all(
56+
target_arch = "wasm32",
57+
not(target_os = "emscripten"),
58+
feature = "wasm-bindgen"
59+
)),
60+
wasm32_bindgen
61+
);
62+
63+
mod_use!(
64+
cfg(all(
65+
target_arch = "wasm32",
66+
not(target_os = "emscripten"),
67+
not(feature = "wasm-bindgen"),
68+
feature = "stdweb",
69+
)),
70+
wasm32_stdweb
71+
);
72+
73+
mod_use!(
74+
cfg(not(any(
75+
target_os = "android",
76+
target_os = "bitrig",
77+
target_os = "cloudabi",
78+
target_os = "dragonfly",
79+
target_os = "emscripten",
80+
target_os = "freebsd",
81+
target_os = "fuchsia",
82+
target_os = "haiku",
83+
target_os = "ios",
84+
target_os = "linux",
85+
target_os = "macos",
86+
target_os = "netbsd",
87+
target_os = "openbsd",
88+
target_os = "redox",
89+
target_os = "solaris",
90+
target_env = "sgx",
91+
windows,
92+
all(
93+
target_arch = "wasm32",
94+
any(
95+
target_os = "emscripten",
96+
feature = "wasm-bindgen",
97+
feature = "stdweb",
98+
),
99+
),
100+
))),
101+
dummy
102+
);

0 commit comments

Comments
 (0)