Skip to content

Commit

Permalink
std: Update randomness implementation on Windows
Browse files Browse the repository at this point in the history
This commit updates the OS random number generator on Windows to match the
upstream implementation in the `rand` crate. First proposed in
rust-random/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 rust-lang#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]: rust-random/rand#111 (comment)
  • Loading branch information
alexcrichton committed Oct 18, 2017
1 parent 7a4f394 commit 55c0173
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 46 deletions.
18 changes: 3 additions & 15 deletions src/libstd/sys/windows/c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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")]
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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,
Expand Down
38 changes: 7 additions & 31 deletions src/libstd/sys/windows/rand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand All @@ -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: {}",
Expand All @@ -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());
}
}
}

0 comments on commit 55c0173

Please sign in to comment.