Skip to content

Commit 283f9f8

Browse files
authored
Add Windows UWP support (#69)
1 parent 86c2cd6 commit 283f9f8

File tree

5 files changed

+101
-1
lines changed

5 files changed

+101
-1
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ matrix:
137137
- cargo xbuild --target=x86_64-unknown-uefi
138138
- cargo xbuild --target=x86_64-unknown-hermit
139139
- cargo xbuild --target=x86_64-unknown-l4re-uclibc
140+
- cargo xbuild --target=x86_64-uwp-windows-gnu
140141

141142
# Trust cross-built/emulated targets. We must repeat all non-default values.
142143
- rust: stable

appveyor.yml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,21 @@ environment:
2121

2222
matrix:
2323
- TARGET: x86_64-pc-windows-msvc
24+
CHANNEL: 1.32.0
25+
- TARGET: x86_64-pc-windows-msvc
26+
CHANNEL: stable
27+
- TARGET: x86_64-pc-windows-msvc
28+
CHANNEL: nightly
2429
- TARGET: i686-pc-windows-msvc
30+
CHANNEL: nightly
31+
- TARGET: x86_64-pc-windows-gnu
32+
CHANNEL: nightly
33+
- TARGET: i686-pc-windows-gnu
34+
CHANNEL: nightly
35+
2536
install:
2637
- appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
27-
- rustup-init.exe -y --default-host %TARGET%
38+
- rustup-init.exe -y --default-host %TARGET% --default-toolchain %CHANNEL%
2839
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
2940
- rustc -V
3041
- cargo -V

build.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#![deny(warnings)]
2+
3+
use std::env;
4+
5+
fn main() {
6+
let target = env::var("TARGET").expect("TARGET was not set");
7+
if target.contains("-uwp-windows-") {
8+
// for BCryptGenRandom
9+
println!("cargo:rustc-link-lib=bcrypt");
10+
// to work around unavailability of `target_vendor` on Rust 1.33
11+
println!("cargo:rustc-cfg=getrandom_uwp");
12+
} else if target.contains("windows") {
13+
// for RtlGenRandom (aka SystemFunction036)
14+
println!("cargo:rustc-link-lib=advapi32");
15+
} else if target.contains("apple-ios") {
16+
// for SecRandomCopyBytes and kSecRandomDefault
17+
println!("cargo:rustc-link-lib=framework=Security");
18+
}
19+
}

src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,14 @@ cfg_if! {
126126
macro_rules! error {
127127
($($x:tt)*) => {};
128128
}
129+
#[allow(unused)]
130+
macro_rules! warn {
131+
($($x:tt)*) => {};
132+
}
133+
#[allow(unused)]
134+
macro_rules! info {
135+
($($x:tt)*) => {};
136+
}
129137
}
130138
}
131139

@@ -202,6 +210,8 @@ cfg_if! {
202210
#[path = "solaris_illumos.rs"] mod imp;
203211
} else if #[cfg(target_os = "wasi")] {
204212
#[path = "wasi.rs"] mod imp;
213+
} else if #[cfg(all(windows, getrandom_uwp))] {
214+
#[path = "windows_uwp.rs"] mod imp;
205215
} else if #[cfg(windows)] {
206216
#[path = "windows.rs"] mod imp;
207217
} else if #[cfg(all(target_arch = "x86_64", any(

src/windows_uwp.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright 2018 Developers of the Rand project.
2+
//
3+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4+
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5+
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6+
// option. This file may not be copied, modified, or distributed
7+
// except according to those terms.
8+
9+
//! Implementation for Windows UWP targets. After deprecation of Windows XP
10+
//! and Vista, this can superseed the `RtlGenRandom`-based implementation.
11+
use crate::Error;
12+
use core::{ffi::c_void, num::NonZeroU32, ptr};
13+
14+
const BCRYPT_USE_SYSTEM_PREFERRED_RNG: u32 = 0x00000002;
15+
16+
extern "system" {
17+
fn BCryptGenRandom(
18+
hAlgorithm: *mut c_void,
19+
pBuffer: *mut u8,
20+
cbBuffer: u32,
21+
dwFlags: u32,
22+
) -> u32;
23+
}
24+
25+
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
26+
// Prevent overflow of u32
27+
for chunk in dest.chunks_mut(u32::max_value() as usize) {
28+
let ret = unsafe {
29+
BCryptGenRandom(
30+
ptr::null_mut(),
31+
chunk.as_mut_ptr(),
32+
chunk.len() as u32,
33+
BCRYPT_USE_SYSTEM_PREFERRED_RNG,
34+
)
35+
};
36+
// NTSTATUS codes use two highest bits for severity status
37+
match ret >> 30 {
38+
0b01 => {
39+
info!("BCryptGenRandom: information code 0x{:08X}", ret);
40+
}
41+
0b10 => {
42+
warn!("BCryptGenRandom: warning code 0x{:08X}", ret);
43+
}
44+
0b11 => {
45+
error!("BCryptGenRandom: failed with 0x{:08X}", ret);
46+
// We zeroize the highest bit, so the error code will reside
47+
// inside the range of designated for OS codes.
48+
let code = ret ^ (1 << 31);
49+
// SAFETY: the second highest bit is always equal to one,
50+
// so it's impossible to get zero. Unfortunately compiler
51+
// is not smart enough to figure out it yet.
52+
let code = unsafe { NonZeroU32::new_unchecked(code) };
53+
return Err(Error::from(code));
54+
}
55+
_ => (),
56+
}
57+
}
58+
Ok(())
59+
}

0 commit comments

Comments
 (0)