about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librand/os.rs208
-rw-r--r--src/rt/rust_builtin.c59
2 files changed, 112 insertions, 155 deletions
diff --git a/src/librand/os.rs b/src/librand/os.rs
index 0b11cfb0ac6..7d9c9e35dfd 100644
--- a/src/librand/os.rs
+++ b/src/librand/os.rs
@@ -11,124 +11,140 @@
 //! Interfaces to the operating system provided random number
 //! generators.
 
-use Rng;
+pub use self::imp::OSRng;
 
 #[cfg(unix)]
-use reader::ReaderRng;
-#[cfg(unix)]
-use std::io::File;
-
-#[cfg(windows)]
-use std::cast;
-#[cfg(windows)]
-use std::libc::{c_long, DWORD, BYTE};
-#[cfg(windows)]
-type HCRYPTPROV = c_long;
-// the extern functions imported from the runtime on Windows are
-// implemented so that they either succeed or abort(), so we can just
-// assume they work when we call them.
-
-/// 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`.
-/// - Windows: calls `CryptGenRandom`, using the default cryptographic
-///   service provider with the `PROV_RSA_FULL` type.
-///
-/// This does not block.
-#[cfg(unix)]
-pub struct OSRng {
-    priv inner: ReaderRng<File>
-}
-/// 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`.
-/// - Windows: calls `CryptGenRandom`, using the default cryptographic
-///   service provider with the `PROV_RSA_FULL` type.
-///
-/// This does not block.
-#[cfg(windows)]
-pub struct OSRng {
-    priv hcryptprov: HCRYPTPROV
-}
-
-impl OSRng {
-    /// Create a new `OSRng`.
+mod imp {
+    use Rng;
+    use reader::ReaderRng;
+    use std::io::File;
+
+    /// 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`.
+    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
+    ///   service provider with the `PROV_RSA_FULL` type.
+    ///
+    /// This does not block.
     #[cfg(unix)]
-    pub fn new() -> OSRng {
-        let reader = File::open(&Path::new("/dev/urandom"));
-        let reader = reader.ok().expect("Error opening /dev/urandom");
-        let reader_rng = ReaderRng::new(reader);
-
-        OSRng { inner: reader_rng }
+    pub struct OSRng {
+        priv inner: ReaderRng<File>
     }
 
-    /// Create a new `OSRng`.
-    #[cfg(windows)]
-    pub fn new() -> OSRng {
-        extern { fn rust_win32_rand_acquire(phProv: *mut HCRYPTPROV); }
-
-        let mut hcp = 0;
-        unsafe {rust_win32_rand_acquire(&mut hcp)};
+    impl OSRng {
+        /// Create a new `OSRng`.
+        pub fn new() -> OSRng {
+            let reader = File::open(&Path::new("/dev/urandom"));
+            let reader = reader.ok().expect("Error opening /dev/urandom");
+            let reader_rng = ReaderRng::new(reader);
 
-        OSRng { hcryptprov: hcp }
+            OSRng { inner: reader_rng }
+        }
     }
-}
 
-#[cfg(unix)]
-impl Rng for OSRng {
-    fn next_u32(&mut self) -> u32 {
-        self.inner.next_u32()
-    }
-    fn next_u64(&mut self) -> u64 {
-        self.inner.next_u64()
-    }
-    fn fill_bytes(&mut self, v: &mut [u8]) {
-        self.inner.fill_bytes(v)
+    impl Rng for OSRng {
+        fn next_u32(&mut self) -> u32 {
+            self.inner.next_u32()
+        }
+        fn next_u64(&mut self) -> u64 {
+            self.inner.next_u64()
+        }
+        fn fill_bytes(&mut self, v: &mut [u8]) {
+            self.inner.fill_bytes(v)
+        }
     }
 }
 
 #[cfg(windows)]
-impl Rng for OSRng {
-    fn next_u32(&mut self) -> u32 {
-        let mut v = [0u8, .. 4];
-        self.fill_bytes(v);
-        unsafe { cast::transmute(v) }
-    }
-    fn next_u64(&mut self) -> u64 {
-        let mut v = [0u8, .. 8];
-        self.fill_bytes(v);
-        unsafe { cast::transmute(v) }
+mod imp {
+    use Rng;
+    use std::cast;
+    use std::libc::{c_ulong, DWORD, BYTE, LPCSTR, BOOL};
+    use std::os;
+
+    type HCRYPTPROV = c_ulong;
+
+    /// 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`.
+    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
+    ///   service provider with the `PROV_RSA_FULL` type.
+    ///
+    /// This does not block.
+    pub struct OSRng {
+        priv hcryptprov: HCRYPTPROV
     }
-    fn fill_bytes(&mut self, v: &mut [u8]) {
-        extern {
-            fn rust_win32_rand_gen(hProv: HCRYPTPROV, dwLen: DWORD,
-                                   pbBuffer: *mut BYTE);
-        }
 
-        unsafe {rust_win32_rand_gen(self.hcryptprov, v.len() as DWORD, v.as_mut_ptr())}
+    static PROV_RSA_FULL: DWORD = 1;
+    static CRYPT_SILENT: DWORD = 64;
+    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;
+
+    extern "system" {
+        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
+                                pszContainer: LPCSTR,
+                                pszProvider: LPCSTR,
+                                dwProvType: DWORD,
+                                dwFlags: DWORD) -> BOOL;
+        fn CryptGenRandom(hProv: HCRYPTPROV,
+                          dwLen: DWORD,
+                          pbBuffer: *mut BYTE) -> BOOL;
+        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
     }
-}
 
-impl Drop for OSRng {
-    #[cfg(unix)]
-    fn drop(&mut self) {
-        // ensure that OSRng is not implicitly copyable on all
-        // platforms, for consistency.
+    impl OSRng {
+        /// Create a new `OSRng`.
+        pub fn new() -> OSRng {
+            let mut hcp = 0;
+            let ret = unsafe {
+                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
+                                     PROV_RSA_FULL,
+                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
+            };
+            if ret == 0 {
+                fail!("couldn't create context: {}", os::last_os_error());
+            }
+            OSRng { hcryptprov: hcp }
+        }
     }
 
-    #[cfg(windows)]
-    fn drop(&mut self) {
-        extern { fn rust_win32_rand_release(hProv: HCRYPTPROV); }
+    impl Rng for OSRng {
+        fn next_u32(&mut self) -> u32 {
+            let mut v = [0u8, .. 4];
+            self.fill_bytes(v);
+            unsafe { cast::transmute(v) }
+        }
+        fn next_u64(&mut self) -> u64 {
+            let mut v = [0u8, .. 8];
+            self.fill_bytes(v);
+            unsafe { cast::transmute(v) }
+        }
+        fn fill_bytes(&mut self, v: &mut [u8]) {
+            let ret = unsafe {
+                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
+                               v.as_mut_ptr())
+            };
+            if ret == 0 {
+                fail!("couldn't generate random bytes: {}", os::last_os_error());
+            }
+        }
+    }
 
-        unsafe {rust_win32_rand_release(self.hcryptprov)}
+    impl Drop for OSRng {
+        fn drop(&mut self) {
+            let ret = unsafe {
+                CryptReleaseContext(self.hcryptprov, 0)
+            };
+            if ret == 0 {
+                fail!("couldn't release context: {}", os::last_os_error());
+            }
+        }
     }
 }
 
-
 #[cfg(test)]
 mod test {
     use super::OSRng;
diff --git a/src/rt/rust_builtin.c b/src/rt/rust_builtin.c
index 8ab8636aa3a..9c27fe1c5e4 100644
--- a/src/rt/rust_builtin.c
+++ b/src/rt/rust_builtin.c
@@ -387,65 +387,6 @@ rust_unset_sigprocmask() {
 
 #endif
 
-#if defined(__WIN32__)
-void
-win32_require(LPCTSTR fn, BOOL ok) {
-    if (!ok) {
-        LPTSTR buf;
-        DWORD err = GetLastError();
-        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
-                      FORMAT_MESSAGE_FROM_SYSTEM |
-                      FORMAT_MESSAGE_IGNORE_INSERTS,
-                      NULL, err,
-                      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-                      (LPTSTR) &buf, 0, NULL );
-        fprintf(stderr, "%s failed with error %ld: %s", fn, err, buf);
-        LocalFree((HLOCAL)buf);
-        abort();
-    }
-}
-
-void
-rust_win32_rand_acquire(HCRYPTPROV* phProv) {
-    win32_require
-        (_T("CryptAcquireContext"),
-         // changes to the parameters here should be reflected in the docs of
-         // rand::os::OSRng
-         CryptAcquireContext(phProv, NULL, NULL, PROV_RSA_FULL,
-                             CRYPT_VERIFYCONTEXT|CRYPT_SILENT));
-
-}
-void
-rust_win32_rand_gen(HCRYPTPROV hProv, DWORD dwLen, BYTE* pbBuffer) {
-    win32_require
-        (_T("CryptGenRandom"), CryptGenRandom(hProv, dwLen, pbBuffer));
-}
-void
-rust_win32_rand_release(HCRYPTPROV hProv) {
-    win32_require
-        (_T("CryptReleaseContext"), CryptReleaseContext(hProv, 0));
-}
-
-#else
-
-// these symbols are listed in rustrt.def.in, so they need to exist; but they
-// should never be called.
-
-void
-rust_win32_rand_acquire() {
-    abort();
-}
-void
-rust_win32_rand_gen() {
-    abort();
-}
-void
-rust_win32_rand_release() {
-    abort();
-}
-
-#endif
-
 //
 // Local Variables:
 // mode: C++