]> git.lizzy.rs Git - rust.git/commitdiff
std: Update randomness implementation on Windows
authorAlex Crichton <alex@alexcrichton.com>
Wed, 18 Oct 2017 18:43:17 +0000 (11:43 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Wed, 18 Oct 2017 18:48:20 +0000 (11:48 -0700)
This commit updates the OS random number generator on Windows to match the
upstream implementation in the `rand` crate. First proposed in
rust-lang-nursery/rand#111 this implementation uses a "private" API of
`RtlGenRandom`. Despite the [documentation][dox] indicating this is a private
function its widespread use in Chromium and Firefox as well as [comments] from
Microsoft internally indicates that it's highly unlikely to break.

Another motivation for switching this is to also attempt to make progress
on #44911. It may be the case that this function succeeds while the previous
implementation may fail in "weird" scenarios.

[dox]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa387694(v=vs.85).aspx
[comments]: https://github.com/rust-lang-nursery/rand/issues/111#issuecomment-316140155

src/libstd/sys/windows/c.rs
src/libstd/sys/windows/rand.rs

index 762e39809ccc06974e5d5158117ba7c13a48053c..39e00270233b41aa14a25e646b67984f5997bd3e 100644 (file)
@@ -37,7 +37,6 @@
 pub type BYTE = u8;
 pub type BOOLEAN = BYTE;
 pub type GROUP = c_uint;
-pub type LONG_PTR = isize;
 pub type LARGE_INTEGER = c_longlong;
 pub type LONG = c_long;
 pub type UINT = c_uint;
@@ -46,7 +45,6 @@
 pub type SIZE_T = usize;
 pub type WORD = u16;
 pub type CHAR = c_char;
-pub type HCRYPTPROV = LONG_PTR;
 pub type ULONG_PTR = usize;
 pub type ULONG = c_ulong;
 #[cfg(target_arch = "x86_64")]
@@ -288,10 +286,6 @@ pub struct ipv6_mreq {
 #[cfg(feature = "backtrace")]
 pub const IMAGE_FILE_MACHINE_AMD64: DWORD = 0x8664;
 
-pub const PROV_RSA_FULL: DWORD = 1;
-pub const CRYPT_SILENT: DWORD = 64;
-pub const CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;
-
 pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0;
 pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd;
 pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
@@ -1136,15 +1130,6 @@ pub fn getaddrinfo(node: *const c_char, service: *const c_char,
     pub fn GetProcAddress(handle: HMODULE,
                           name: LPCSTR) -> *mut c_void;
     pub fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;
-    pub fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
-                                pszContainer: LPCSTR,
-                                pszProvider: LPCSTR,
-                                dwProvType: DWORD,
-                                dwFlags: DWORD) -> BOOL;
-    pub fn CryptGenRandom(hProv: HCRYPTPROV,
-                          dwLen: DWORD,
-                          pbBuffer: *mut BYTE) -> BOOL;
-    pub fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
 
     pub fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: LPFILETIME);
 
@@ -1175,6 +1160,9 @@ pub fn select(nfds: c_int,
                   writefds: *mut fd_set,
                   exceptfds: *mut fd_set,
                   timeout: *const timeval) -> c_int;
+
+    #[link_name = "SystemFunction036"]
+    pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN;
 }
 
 // Functions that aren't available on every version of Windows that we support,
index 10e3d45f9d5eb8813bbfa72b59661a7c93e5f732..f66b0a3bdc3f4d382a8e422d771b8b33593c97a1 100644 (file)
 use rand::Rng;
 use sys::c;
 
-pub struct OsRng {
-    hcryptprov: c::HCRYPTPROV
-}
+pub struct OsRng;
 
 impl OsRng {
     /// Create a new `OsRng`.
     pub fn new() -> io::Result<OsRng> {
-        let mut hcp = 0;
-        let ret = unsafe {
-            c::CryptAcquireContextA(&mut hcp, 0 as c::LPCSTR, 0 as c::LPCSTR,
-                                    c::PROV_RSA_FULL,
-                                    c::CRYPT_VERIFYCONTEXT | c::CRYPT_SILENT)
-        };
-
-        if ret == 0 {
-            Err(io::Error::last_os_error())
-        } else {
-            Ok(OsRng { hcryptprov: hcp })
-        }
+        Ok(OsRng)
     }
 }
 
@@ -42,18 +29,19 @@ fn next_u32(&mut self) -> u32 {
         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]) {
-        // CryptGenRandom takes a DWORD (u32) for the length so we need to
+        // RtlGenRandom takes an ULONG (u32) for the length so we need to
         // split up the buffer.
-        for slice in v.chunks_mut(<c::DWORD>::max_value() as usize) {
+        for slice in v.chunks_mut(<c::ULONG>::max_value() as usize) {
             let ret = unsafe {
-                c::CryptGenRandom(self.hcryptprov, slice.len() as c::DWORD,
-                                  slice.as_mut_ptr())
+                c::RtlGenRandom(slice.as_mut_ptr(), slice.len() as c::ULONG)
             };
             if ret == 0 {
                 panic!("couldn't generate random bytes: {}",
@@ -62,15 +50,3 @@ fn fill_bytes(&mut self, v: &mut [u8]) {
         }
     }
 }
-
-impl Drop for OsRng {
-    fn drop(&mut self) {
-        let ret = unsafe {
-            c::CryptReleaseContext(self.hcryptprov, 0)
-        };
-        if ret == 0 {
-            panic!("couldn't release context: {}",
-                   io::Error::last_os_error());
-        }
-    }
-}