commit d3d6761e4367df3fc72f33681c36dc67471cf63f (tree)
parent 52141fe85f1b7719cecb868520f40431fcfff2a1
Author: Andrew Kelley <andrew@ziglang.org>
Date: Mon, 5 Jan 2026 12:16:54 -0800
std: depend on NtDll rather than advapi32.dll for entropy
Diffstat:
4 files changed, 58 insertions(+), 31 deletions(-)
diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig
@@ -13674,7 +13674,7 @@ fn getNulHandle(t: *Threaded) !windows.HANDLE {
const device_path = [_]u16{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'N', 'u', 'l', 'l' };
var nt_name: windows.UNICODE_STRING = .{
.Length = device_path.len * 2,
- .MaximumLength = device_path.len * 2,
+ .MaximumLength = 0,
.Buffer = @constCast(&device_path),
};
const attr: windows.OBJECT_ATTRIBUTES = .{
diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig
@@ -1080,6 +1080,9 @@ pub const CTL_CODE = packed struct(ULONG) {
};
pub const IOCTL = struct {
+ pub const KSEC = struct {
+ pub const GEN_RANDOM: CTL_CODE = .{ .DeviceType = .KSEC, .Function = 2, .Method = .BUFFERED, .Access = .ANY };
+ };
pub const MOUNTMGR = struct {
pub const QUERY_POINTS: CTL_CODE = .{ .DeviceType = .MOUNTMGRCONTROLTYPE, .Function = 2, .Method = .BUFFERED, .Access = .ANY };
pub const QUERY_DOS_VOLUME_PATH: CTL_CODE = .{ .DeviceType = .MOUNTMGRCONTROLTYPE, .Function = 12, .Method = .BUFFERED, .Access = .ANY };
@@ -2644,30 +2647,59 @@ pub fn SetHandleInformation(h: HANDLE, mask: DWORD, flags: DWORD) SetHandleInfor
}
}
-pub const RtlGenRandomError = error{
- /// `RtlGenRandom` has been known to fail in situations where the system is under heavy load.
- /// Unfortunately, it does not call `SetLastError`, so it is not possible to get more specific
- /// error information; it could actually be due to an out-of-memory condition, for example.
- SystemResources,
-};
-
-/// Call RtlGenRandom() instead of CryptGetRandom() on Windows
-/// https://github.com/rust-lang-nursery/rand/issues/111
-/// https://bugzilla.mozilla.org/show_bug.cgi?id=504270
-pub fn RtlGenRandom(output: []u8) RtlGenRandomError!void {
- var total_read: usize = 0;
- var buff: []u8 = output[0..];
- const max_read_size: ULONG = maxInt(ULONG);
-
- while (total_read < output.len) {
- const to_read: ULONG = @min(buff.len, max_read_size);
-
- if (advapi32.RtlGenRandom(buff.ptr, to_read) == 0) {
- return error.SystemResources;
- }
-
- total_read += to_read;
- buff = buff[to_read..];
+/// An alternate implementation of ProcessPrng from bcryptprimitives.dll
+/// This one has the following differences:
+/// * does not heap allocate `buffer`
+/// * does not introduce a dependency on bcryptprimitives.dll, which apparently
+/// runs a test suite every time it is loaded
+/// * reads buffer.len bytes from "\\Device\\CNG" rather than seeding a per-CPU
+/// AES csprng with 48 bytes.
+pub fn ProcessPrng(buffer: []u8) error{Unexpected}!void {
+ const device_path = [_]u16{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'C', 'N', 'G' };
+ var nt_name: UNICODE_STRING = .{
+ .Length = device_path.len * 2,
+ .MaximumLength = 0,
+ .Buffer = @constCast(&device_path),
+ };
+ var cng_device: HANDLE = undefined;
+ var io_status_block: IO_STATUS_BLOCK = undefined;
+ switch (ntdll.NtOpenFile(
+ &cng_device,
+ .{
+ .STANDARD = .{ .SYNCHRONIZE = true },
+ .SPECIFIC = .{ .FILE = .{ .READ_DATA = true } },
+ },
+ &.{
+ .Length = @sizeOf(OBJECT_ATTRIBUTES),
+ .RootDirectory = null,
+ .ObjectName = &nt_name,
+ .Attributes = .{},
+ .SecurityDescriptor = null,
+ .SecurityQualityOfService = null,
+ },
+ &io_status_block,
+ .VALID_FLAGS,
+ .{ .IO = .SYNCHRONOUS_NONALERT },
+ )) {
+ .SUCCESS => {},
+ .OBJECT_NAME_NOT_FOUND => return error.Unexpected, // Observed on wine 10.0
+ else => |status| return unexpectedStatus(status),
+ }
+ defer _ = ntdll.NtClose(cng_device);
+ switch (ntdll.NtDeviceIoControlFile(
+ cng_device,
+ null,
+ null,
+ null,
+ &io_status_block,
+ IOCTL.KSEC.GEN_RANDOM,
+ null,
+ 0,
+ buffer.ptr,
+ @intCast(buffer.len),
+ )) {
+ .SUCCESS => {},
+ else => |status| return unexpectedStatus(status),
}
}
diff --git a/lib/std/os/windows/advapi32.zig b/lib/std/os/windows/advapi32.zig
@@ -28,11 +28,6 @@ pub extern "advapi32" fn RegQueryValueExW(
pub extern "advapi32" fn RegCloseKey(hKey: HKEY) callconv(.winapi) LSTATUS;
-// RtlGenRandom is known as SystemFunction036 under advapi32
-// http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx */
-pub extern "advapi32" fn SystemFunction036(output: [*]u8, length: ULONG) callconv(.winapi) BOOL;
-pub const RtlGenRandom = SystemFunction036;
-
pub const RRF = struct {
pub const RT_ANY: DWORD = 0x0000ffff;
diff --git a/lib/std/posix.zig b/lib/std/posix.zig
@@ -370,7 +370,7 @@ pub const GetRandomError = OpenError;
/// library implementation.
pub fn getrandom(buffer: []u8) GetRandomError!void {
if (native_os == .windows) {
- return windows.RtlGenRandom(buffer);
+ return windows.ProcessPrng(buffer);
}
if (builtin.link_libc and @TypeOf(system.arc4random_buf) != void) {
system.arc4random_buf(buffer.ptr, buffer.len);