summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-12-19 23:21:12 +0000
committerbors <bors@rust-lang.org>2015-12-19 23:21:12 +0000
commitabf60b20aa0edcae6d206905b1a1129e86dc60b3 (patch)
tree21d853d07db83ace8f209292e0e67ae082976236 /src/libstd
parentcef0d0f9a88e241423c30ae89a0f66aade257391 (diff)
parent9fde3e9b94e19426a319af33b330a5cb87340c46 (diff)
downloadrust-abf60b20aa0edcae6d206905b1a1129e86dc60b3.tar.gz
rust-abf60b20aa0edcae6d206905b1a1129e86dc60b3.zip
Auto merge of #30430 - mmcco:master, r=alexcrichton
Rust already supports Linux's getrandom(2), which is very similar and
was based on getentropy(2). This is a pretty clean, simple addition that
uses the same approach as the iOS randomness API support.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/rand/mod.rs1
-rw-r--r--src/libstd/rand/os.rs62
2 files changed, 62 insertions, 1 deletions
diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs
index 7a4a0f96b30..21e60420c18 100644
--- a/src/libstd/rand/mod.rs
+++ b/src/libstd/rand/mod.rs
@@ -47,6 +47,7 @@
 //!     if the entropy pool is very small, such as immediately after first booting.
 //!     Linux 3.17 added the `getrandom(2)` system call which solves the issue: it blocks if entropy
 //!     pool is not initialized yet, but it does not block once initialized.
+//!     `getrandom(2)` was based on `getentropy(2)`, an existing system call in OpenBSD.
 //!     `OsRng` tries to use `getrandom(2)` if available, and use `/dev/urandom` fallback if not.
 //!     If an application does not have `getrandom` and likely to be run soon after first booting,
 //!     or on a system with very few entropy sources, one should consider using `/dev/random` via
diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs
index c4f59d51f5d..13965ce810d 100644
--- a/src/libstd/rand/os.rs
+++ b/src/libstd/rand/os.rs
@@ -13,7 +13,7 @@
 
 pub use self::imp::OsRng;
 
-#[cfg(all(unix, not(target_os = "ios")))]
+#[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd")))]
 mod imp {
     use self::OsRngInner::*;
 
@@ -131,6 +131,7 @@ mod imp {
     /// - Windows: calls `CryptGenRandom`, using the default cryptographic
     ///   service provider with the `PROV_RSA_FULL` type.
     /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
+    /// - OpenBSD: uses the `getentropy(2)` system call.
     ///
     /// This does not block.
     pub struct OsRng {
@@ -178,6 +179,63 @@ mod imp {
     }
 }
 
+#[cfg(target_os = "openbsd")]
+mod imp {
+    use io;
+    use mem;
+    use libc::c_long;
+    use sys::os::errno;
+    use rand::Rng;
+
+    /// A random number generator that retrieves randomness straight from
+    /// the operating system. Platform sources:
+    ///
+    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
+    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
+    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
+    ///   service provider with the `PROV_RSA_FULL` type.
+    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
+    /// - OpenBSD: uses the `getentropy(2)` system call.
+    ///
+    /// This does not block.
+    pub struct OsRng {
+        // dummy field to ensure that this struct cannot be constructed outside
+        // of this module
+        _dummy: (),
+    }
+
+    impl OsRng {
+        /// Create a new `OsRng`.
+        pub fn new() -> io::Result<OsRng> {
+            Ok(OsRng { _dummy: () })
+        }
+    }
+
+    impl Rng for OsRng {
+        fn next_u32(&mut self) -> u32 {
+            let mut v = [0; 4];
+            self.fill_bytes(&mut v);
+            unsafe { mem::transmute(v) }
+        }
+        fn next_u64(&mut self) -> u64 {
+            let mut v = [0; 8];
+            self.fill_bytes(&mut v);
+            unsafe { mem::transmute(v) }
+        }
+        fn fill_bytes(&mut self, v: &mut [u8]) {
+            // getentropy(2) permits a maximum buffer size of 256 bytes
+            for s in v.chunks_mut(256) {
+                let ret = unsafe {
+                    libc::syscall(libc::NR_GETENTROPY, s.as_mut_ptr(), s.len())
+                };
+                if ret == -1 {
+                    panic!("unexpected getentropy error: {}", errno());
+                }
+            }
+        }
+    }
+}
+
 #[cfg(target_os = "ios")]
 mod imp {
     #[cfg(stage0)] use prelude::v1::*;
@@ -196,6 +254,7 @@ mod imp {
     /// - Windows: calls `CryptGenRandom`, using the default cryptographic
     ///   service provider with the `PROV_RSA_FULL` type.
     /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
+    /// - OpenBSD: uses the `getentropy(2)` system call.
     ///
     /// This does not block.
     pub struct OsRng {
@@ -261,6 +320,7 @@ mod imp {
     /// - Windows: calls `CryptGenRandom`, using the default cryptographic
     ///   service provider with the `PROV_RSA_FULL` type.
     /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
+    /// - OpenBSD: uses the `getentropy(2)` system call.
     ///
     /// This does not block.
     pub struct OsRng {