Skip to content

Crate implementation #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Feb 14, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
[package]
name = "getrandom"
version = "0.0.0"
version = "0.1.0"
authors = ["The Rand Project Developers"]
license = "MIT/Apache-2.0"
edition = "2015"
license = "MIT OR Apache-2.0"
description = "A small cross-platform library to securely get random data (entropy)"

[dependencies]
[badges]
travis-ci = { repository = "rust-random/getrandom" }
appveyor = { repository = "rust-random/getrandom" }

[target.'cfg(unix)'.dependencies]
libc = "0.2"

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["minwindef", "ntsecapi", "winnt"] }

[target.wasm32-unknown-unknown.dependencies]
wasm-bindgen = { version = "0.2.12", optional = true }
stdweb = { version = "0.4", optional = true }
21 changes: 21 additions & 0 deletions src/cloudabi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use error::Error;

extern "C" {
fn cloudabi_sys_random_get(buf: *mut u8, len: usize) -> u16;
}

pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
let errno = unsafe { cloudabi_sys_random_get(dest.as_ptr(), dest.len()) };
if errno == 0 {
Ok(())
} else {
Err(Error::Unknown)
}
}
31 changes: 31 additions & 0 deletions src/dragonfly_haiku.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation for DragonFly / Haiku
use super::Error;
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(())
}
}).map_err(|_| Error::Unknown)
}
15 changes: 15 additions & 0 deletions src/dummy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A dummy implementation for unsupported targets which always returns
//! `Err(Error::Unavailable)`
use super::Error;

pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
Err(Error::Unavailable)
}
38 changes: 38 additions & 0 deletions src/emscripten.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation for DragonFly / Haiku / Emscripten
use super::Error;
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> {
// `Crypto.getRandomValues` documents `dest` should be at most 65536
// 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(())
}
}).map_err(|_| Error::Unknown)?;
}
Ok(())
}
21 changes: 21 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Error {
/// Call was interrupted.
///
/// Typically it can be retried.
Interrupted,
/// RNG source is unavailable on a given system.
Unavailable,
/// Unknown error.
Unknown,
#[doc(hidden)]
__Nonexhaustive,
}
31 changes: 31 additions & 0 deletions src/freebsd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation for FreeBSD
extern crate libc;

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

pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
let mib = [libc::CTL_KERN, libc::KERN_ARND];
// kern.arandom permits a maximum buffer size of 256 bytes
for chunk in dest.chunks_mut(256) {
let mut len = chunk.len();
let ret = unsafe {
libc::sysctl(
mib.as_ptr(), mib.len() as libc::c_uint,
chunk.as_mut_ptr() as *mut _, &mut len, ptr::null(), 0,
)
};
if ret == -1 || len != chunk.len() {
return Err(Error::Unknown);
}
}
Ok(())
}
22 changes: 22 additions & 0 deletions src/fuchsia.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation for Fuchsia Zircon
use super::Error;

#[link(name = "zircon")]
extern {
fn zx_cprng_draw(buffer: *mut u8, len: usize);
}

pub fn getrandom(&mut self, dest: &mut [u8]) -> Result<(), Error> {
for chunk in dest.chunks(256) {
unsafe { zx_cprng_draw(chunk.as_mut_ptr(), chunk.len()) };
}
Ok(())
}
150 changes: 150 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,153 @@
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.


#![no_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",
))]
#[macro_use] extern crate std;

mod error;
pub use error::Error;

macro_rules! mod_use {
($cond:meta, $module:ident) => {
#[$cond]
mod $module;
#[$cond]
pub use $module::getrandom;
}
}

mod_use!(cfg(target_os = "android"), linux_android);
mod_use!(cfg(target_os = "bitrig"), openbsd_bitrig);
mod_use!(cfg(target_os = "cloudabi"), cloudabi);
mod_use!(cfg(target_os = "dragonfly"), dragonfly_haiku);
mod_use!(cfg(target_os = "emscripten"), emscripten);
mod_use!(cfg(target_os = "freebsd"), freebsd);
mod_use!(cfg(target_os = "fuchsia"), fuchsia);
mod_use!(cfg(target_os = "haiku"), dragonfly_haiku);
mod_use!(cfg(target_os = "ios"), macos);
mod_use!(cfg(target_os = "linux"), linux_android);
mod_use!(cfg(target_os = "macos"), macos);
mod_use!(cfg(target_os = "netbsd"), netbsd);
mod_use!(cfg(target_os = "openbsd"), openbsd_bitrig);
mod_use!(cfg(target_os = "redox"), redox);
mod_use!(cfg(target_os = "solaris"), solaris);
mod_use!(cfg(windows), windows);
mod_use!(cfg(target_env = "sgx"), sgx);

mod_use!(
cfg(all(
target_arch = "wasm32",
not(target_os = "emscripten"),
feature = "wasm-bindgen"
)),
wasm32_bindgen
);

mod_use!(
cfg(all(
target_arch = "wasm32",
not(target_os = "emscripten"),
not(feature = "wasm-bindgen"),
feature = "stdweb",
)),
wasm32_stdweb
);

mod_use!(
cfg(not(any(
target_os = "android",
target_os = "bitrig",
target_os = "cloudabi",
target_os = "dragonfly",
target_os = "emscripten",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "haiku",
target_os = "ios",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_env = "sgx",
windows,
all(
target_arch = "wasm32",
any(
target_os = "emscripten",
feature = "wasm-bindgen",
feature = "stdweb",
),
),
))),
dummy
);

// Due to rustwasm/wasm-bindgen#201 this can't be defined in the inner os
// modules, so hack around it for now and place it at the root.
#[cfg(all(feature = "wasm-bindgen", target_arch = "wasm32"))]
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub mod __wbg_shims {

// `extern { type Foo; }` isn't supported on 1.22 syntactically, so use a
// macro to work around that.
macro_rules! rust_122_compat {
($($t:tt)*) => ($($t)*)
}

rust_122_compat! {
extern crate wasm_bindgen;

pub use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" {
pub type Function;
#[wasm_bindgen(constructor)]
pub fn new(s: &str) -> Function;
#[wasm_bindgen(method)]
pub fn call(this: &Function, self_: &JsValue) -> JsValue;

pub type This;
#[wasm_bindgen(method, getter, structural, js_name = self)]
pub fn self_(me: &This) -> JsValue;
#[wasm_bindgen(method, getter, structural)]
pub fn crypto(me: &This) -> JsValue;

#[derive(Clone, Debug)]
pub type BrowserCrypto;

// TODO: these `structural` annotations here ideally wouldn't be here to
// avoid a JS shim, but for now with feature detection they're
// unavoidable.
#[wasm_bindgen(method, js_name = getRandomValues, structural, getter)]
pub fn get_random_values_fn(me: &BrowserCrypto) -> JsValue;
#[wasm_bindgen(method, js_name = getRandomValues, structural)]
pub fn get_random_values(me: &BrowserCrypto, buf: &mut [u8]);

#[wasm_bindgen(js_name = require)]
pub fn node_require(s: &str) -> NodeCrypto;

#[derive(Clone, Debug)]
pub type NodeCrypto;

#[wasm_bindgen(method, js_name = randomFillSync, structural)]
pub fn random_fill_sync(me: &NodeCrypto, buf: &mut [u8]);
}
}
}
Loading