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; +mod imp { + use Rng; + use reader::ReaderRng; + 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 -} -/// 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`. + /// 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 } - /// Create a new `OSRng`. - #[cfg(windows)] - pub fn new() -> OSRng { - extern { fn rust_win32_rand_acquire(phProv: *mut HCRYPTPROV); } + 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); - let mut hcp = 0; - unsafe {rust_win32_rand_acquire(&mut hcp)}; - - OSRng { hcryptprov: hcp } - } -} - -#[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) - } -} - -#[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) } - } - fn fill_bytes(&mut self, v: &mut [u8]) { - extern { - fn rust_win32_rand_gen(hProv: HCRYPTPROV, dwLen: DWORD, - pbBuffer: *mut BYTE); + OSRng { inner: reader_rng } } + } - unsafe {rust_win32_rand_gen(self.hcryptprov, v.len() as DWORD, v.as_mut_ptr())} + 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 Drop for OSRng { - #[cfg(unix)] - fn drop(&mut self) { - // ensure that OSRng is not implicitly copyable on all - // platforms, for consistency. +#[cfg(windows)] +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 } - #[cfg(windows)] - fn drop(&mut self) { - extern { fn rust_win32_rand_release(hProv: HCRYPTPROV); } + static PROV_RSA_FULL: DWORD = 1; + static CRYPT_SILENT: DWORD = 64; + static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000; - unsafe {rust_win32_rand_release(self.hcryptprov)} + 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 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 } + } + } + + 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()); + } + } + } + + 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++