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:
commit
cc03782b93
@ -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,
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user