summaryrefslogtreecommitdiff
path: root/src/rust
diff options
context:
space:
mode:
Diffstat (limited to 'src/rust')
-rw-r--r--src/rust/Cargo.lock30
-rw-r--r--src/rust/Cargo.toml4
-rw-r--r--src/rust/external/crypto_rand.rs87
-rw-r--r--src/rust/external/lib.rs4
-rw-r--r--src/rust/rand/Cargo.toml27
-rw-r--r--src/rust/rand/lib.rs16
-rw-r--r--src/rust/rand/rng.rs140
7 files changed, 306 insertions, 2 deletions
diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock
index 91c0502c60..1480cf7962 100644
--- a/src/rust/Cargo.lock
+++ b/src/rust/Cargo.lock
@@ -23,6 +23,35 @@ dependencies = [
]
[[package]]
+name = "rand"
+version = "0.0.1"
+dependencies = [
+ "external 0.0.1",
+ "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.5.0-pre.0",
+ "rand_core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tor_allocate 0.0.1",
+ "tor_log 0.1.0",
+ "tor_util 0.0.1",
+]
+
+[[package]]
+name = "rand"
+version = "0.5.0-pre.0"
+dependencies = [
+ "rand_core 0.1.0",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.1.0"
+
+[[package]]
+name = "rand_core"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "smartlist"
version = "0.0.1"
dependencies = [
@@ -63,3 +92,4 @@ dependencies = [
[metadata]
"checksum libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)" = "f54263ad99207254cf58b5f701ecb432c717445ea2ee8af387334bdd1a03fdff"
+"checksum rand_core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0224284424a4b818387b58d59336c288f99b48f69681aa60cc681fe038bbca5d"
diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml
index 4ae8033eb3..d47cd64223 100644
--- a/src/rust/Cargo.toml
+++ b/src/rust/Cargo.toml
@@ -1,6 +1,8 @@
[workspace]
members = ["tor_util", "protover", "smartlist", "external", "tor_allocate",
-"tor_rust", "tor_log"]
+"tor_rust", "tor_log",
+ "rand",
+]
[profile.release]
debug = true
diff --git a/src/rust/external/crypto_rand.rs b/src/rust/external/crypto_rand.rs
new file mode 100644
index 0000000000..af1ade0161
--- /dev/null
+++ b/src/rust/external/crypto_rand.rs
@@ -0,0 +1,87 @@
+// Copyright (c) 2018, The Tor Project, Inc.
+// Copyright (c) 2018, isis agora lovecruft
+// See LICENSE for licensing information
+
+//! Bindings to external (P)RNG interfaces and utilities in
+//! src/common/crypto_rand.[ch].
+//!
+//! We wrap our C implementations in src/common/crypto_rand.[ch] here in order
+//! to provide wrappers with native Rust types, and then provide more Rusty
+//! types and and trait implementations in src/rust/crypto/rand/.
+
+use std::time::Duration;
+
+use libc::c_double;
+use libc::c_int;
+use libc::size_t;
+use libc::time_t;
+use libc::uint8_t;
+
+extern "C" {
+ fn crypto_seed_rng() -> c_int;
+ fn crypto_rand(out: *mut uint8_t, out_len: size_t);
+ fn crypto_strongest_rand(out: *mut uint8_t, out_len: size_t);
+ fn crypto_rand_time_range(min: time_t, max: time_t) -> time_t;
+ fn crypto_rand_double() -> c_double;
+}
+
+/// Seed OpenSSL's random number generator with bytes from the operating
+/// system.
+///
+/// # Returns
+///
+/// `true` on success; `false` on failure.
+pub fn c_tor_crypto_seed_rng() -> bool {
+ let ret: c_int;
+
+ unsafe {
+ ret = crypto_seed_rng();
+ }
+ match ret {
+ 0 => return true,
+ _ => return false,
+ }
+}
+
+/// Fill the bytes of `dest` with random data.
+pub fn c_tor_crypto_rand(dest: &mut [u8]) {
+ unsafe {
+ crypto_rand(dest.as_mut_ptr(), dest.len() as size_t);
+ }
+}
+
+/// Fill the bytes of `dest` with "strong" random data by hashing
+/// together randomness obtained from OpenSSL's RNG and the operating
+/// system.
+pub fn c_tor_crypto_strongest_rand(dest: &mut [u8]) {
+ // We'll let the C side panic if the len is larger than
+ // MAX_STRONGEST_RAND_SIZE, rather than potentially panicking here. A
+ // paranoid caller should assert on the length of dest *before* calling this
+ // function.
+ unsafe {
+ crypto_strongest_rand(dest.as_mut_ptr(), dest.len() as size_t);
+ }
+}
+
+/// Get a random time, in seconds since the Unix Epoch.
+///
+/// # Returns
+///
+/// A `std::time::Duration` of seconds since the Unix Epoch.
+pub fn c_tor_crypto_rand_time_range(min: &Duration, max: &Duration) -> Duration {
+ let ret: time_t;
+
+ unsafe {
+ ret = crypto_rand_time_range(min.as_secs() as time_t, max.as_secs() as time_t);
+ }
+
+ Duration::from_secs(ret as u64)
+}
+
+/// Return a pseudorandom 64-bit float, chosen uniformly from the range [0.0, 1.0).
+pub fn c_tor_crypto_rand_double() -> f64 {
+ unsafe {
+ crypto_rand_double()
+ }
+}
+
diff --git a/src/rust/external/lib.rs b/src/rust/external/lib.rs
index 0af0d6452d..5fd74cf4c2 100644
--- a/src/rust/external/lib.rs
+++ b/src/rust/external/lib.rs
@@ -1,4 +1,4 @@
-//! Copyright (c) 2016-2017, The Tor Project, Inc. */
+//! Copyright (c) 2016-2018, The Tor Project, Inc. */
//! See LICENSE for licensing information */
//! Interface for external calls to tor C ABI
@@ -9,6 +9,8 @@
extern crate libc;
+mod crypto_rand;
mod external;
+pub use crypto_rand::*;
pub use external::*;
diff --git a/src/rust/rand/Cargo.toml b/src/rust/rand/Cargo.toml
new file mode 100644
index 0000000000..1b73563c8d
--- /dev/null
+++ b/src/rust/rand/Cargo.toml
@@ -0,0 +1,27 @@
+# TODO: Note that this package should be merged into the "crypto" crate after #24659 is merged.
+
+[package]
+authors = ["The Tor Project"]
+version = "0.0.1"
+name = "rand"
+publish = false
+
+[features]
+testing = ["tor_log/testing"]
+
+[dependencies]
+libc = "=0.2.39"
+rand_core = "=0.1.0"
+
+external = { path = "../external" }
+tor_allocate = { path = "../tor_allocate" }
+tor_log = { path = "../tor_log" }
+tor_util = { path = "../tor_util" }
+
+[dev-dependencies]
+rand = { version = "=0.5.0-pre.0", default-features = false, path = "../../ext/rust/vendor/rand-8c5b0ac51d" }
+
+[lib]
+name = "rand"
+path = "lib.rs"
+crate_type = ["rlib", "staticlib"]
diff --git a/src/rust/rand/lib.rs b/src/rust/rand/lib.rs
new file mode 100644
index 0000000000..6b3058ad58
--- /dev/null
+++ b/src/rust/rand/lib.rs
@@ -0,0 +1,16 @@
+// Copyright (c) 2018, The Tor Project, Inc.
+// Copyright (c) 2018, isis agora lovecruft
+// See LICENSE for licensing information
+
+// External dependencies
+#[cfg(test)]
+extern crate rand;
+extern crate rand_core;
+
+// Internal dependencies
+extern crate external;
+#[cfg(not(test))]
+#[macro_use]
+extern crate tor_log;
+
+pub mod rng;
diff --git a/src/rust/rand/rng.rs b/src/rust/rand/rng.rs
new file mode 100644
index 0000000000..cfd96c9617
--- /dev/null
+++ b/src/rust/rand/rng.rs
@@ -0,0 +1,140 @@
+// Copyright (c) 2018, The Tor Project, Inc.
+// Copyright (c) 2018, isis agora lovecruft
+// See LICENSE for licensing information
+
+//! Wrappers for Tor's random number generators to provide implementations of
+//! `rand_core` traits.
+
+// This is the real implementation, in use in production, which calls into our C
+// wrappers in /src/common/crypto_rand.c, which call into OpenSSL, system
+// libraries, and make syscalls.
+#[cfg(not(test))]
+mod internal {
+ use std::u64;
+
+ use rand_core::CryptoRng;
+ use rand_core::Error;
+ use rand_core::RngCore;
+ use rand_core::impls::next_u32_via_fill;
+ use rand_core::impls::next_u64_via_fill;
+
+ use external::c_tor_crypto_rand;
+ use external::c_tor_crypto_strongest_rand;
+ use external::c_tor_crypto_seed_rng;
+
+ use tor_log::LogDomain;
+ use tor_log::LogSeverity;
+
+ /// Largest strong entropy request permitted.
+ //
+ // C_RUST_COUPLED: `MAX_STRONGEST_RAND_SIZE` /src/common/crypto_rand.c
+ const MAX_STRONGEST_RAND_SIZE: usize = 256;
+
+ /// A wrapper around OpenSSL's RNG.
+ pub struct TorRng {
+ // This private, zero-length field forces the struct to be treated the
+ // same as its opaque C couterpart.
+ _unused: [u8; 0],
+ }
+
+ /// Mark `TorRng` as being suitable for cryptographic purposes.
+ impl CryptoRng for TorRng {}
+
+ impl TorRng {
+ // C_RUST_COUPLED: `crypto_seed_rng()` /src/common/crypto_rand.c
+ #[allow(dead_code)]
+ fn new() -> Self {
+ if !c_tor_crypto_seed_rng() {
+ tor_log_msg!(LogSeverity::Warn, LogDomain::General,
+ "TorRng::from_seed()",
+ "The RNG could not be seeded!");
+ }
+ // XXX also log success at info level —isis
+ TorRng{ _unused: [0u8; 0] }
+ }
+ }
+
+ impl RngCore for TorRng {
+ // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
+ fn next_u32(&mut self) -> u32 {
+ next_u32_via_fill(self)
+ }
+
+ // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
+ fn next_u64(&mut self) -> u64 {
+ next_u64_via_fill(self)
+ }
+
+ // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ c_tor_crypto_rand(dest);
+ }
+
+ // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ Ok(self.fill_bytes(dest))
+ }
+ }
+
+ /// A CSPRNG which hashes together randomness from OpenSSL's RNG and entropy
+ /// obtained from the operating system.
+ pub struct TorStrongestRng {
+ // This private, zero-length field forces the struct to be treated the
+ // same as its opaque C couterpart.
+ _unused: [u8; 0],
+ }
+
+ /// Mark `TorRng` as being suitable for cryptographic purposes.
+ impl CryptoRng for TorStrongestRng {}
+
+ impl TorStrongestRng {
+ // C_RUST_COUPLED: `crypto_seed_rng()` /src/common/crypto_rand.c
+ #[allow(dead_code)]
+ fn new() -> Self {
+ if !c_tor_crypto_seed_rng() {
+ tor_log_msg!(LogSeverity::Warn, LogDomain::General,
+ "TorStrongestRng::from_seed()",
+ "The RNG could not be seeded!");
+ }
+ // XXX also log success at info level —isis
+ TorStrongestRng{ _unused: [0u8; 0] }
+ }
+ }
+
+ impl RngCore for TorStrongestRng {
+ // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
+ fn next_u32(&mut self) -> u32 {
+ next_u32_via_fill(self)
+ }
+
+ // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
+ fn next_u64(&mut self) -> u64 {
+ next_u64_via_fill(self)
+ }
+
+ // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ debug_assert!(dest.len() <= MAX_STRONGEST_RAND_SIZE);
+
+ c_tor_crypto_strongest_rand(dest);
+ }
+
+ // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ Ok(self.fill_bytes(dest))
+ }
+ }
+}
+
+// For testing, we expose a pure-Rust implementation.
+#[cfg(test)]
+mod internal {
+ // It doesn't matter if we pretend ChaCha is a CSPRNG in tests.
+ pub use rand::ChaChaRng as TorRng;
+ pub use rand::ChaChaRng as TorStrongestRng;
+}
+
+// Finally, expose the public functionality of whichever appropriate internal
+// module.
+pub use self::internal::*;
+