Auto merge of #45370 - alexcrichton:update-windows-rand, r=sfackler

std: Update randomness implementation on Windows

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
This commit is contained in:
bors 2017-10-21 04:33:32 +00:00
commit cc03782b93
2 changed files with 10 additions and 46 deletions

View File

@ -37,7 +37,6 @@ pub type BOOL = c_int;
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 USHORT = c_ushort;
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 const IMAGE_FILE_MACHINE_I386: DWORD = 0x014c;
#[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 @@ extern "system" {
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 @@ extern "system" {
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,

View File

@ -14,25 +14,12 @@ use mem;
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 @@ impl Rng for OsRng {
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 @@ impl Rng for OsRng {
}
}
}
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());
}
}
}