authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-05 12:16:54-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-05 12:16:54-08:00
logd3d6761e4367df3fc72f33681c36dc67471cf63f
tree9ed98c325bc6596e0f1653266768794982f183cc
parent52141fe85f1b7719cecb868520f40431fcfff2a1

std: depend on NtDll rather than advapi32.dll for entropy


4 files changed, 58 insertions(+), 31 deletions(-)

lib/std/Io/Threaded.zig+1-1
......@@ -13674,7 +13674,7 @@ fn getNulHandle(t: *Threaded) !windows.HANDLE {
1367413674 const device_path = [_]u16{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'N', 'u', 'l', 'l' };
1367513675 var nt_name: windows.UNICODE_STRING = .{
1367613676 .Length = device_path.len * 2,
13677 .MaximumLength = device_path.len * 2,
13677 .MaximumLength = 0,
1367813678 .Buffer = @constCast(&device_path),
1367913679 };
1368013680 const attr: windows.OBJECT_ATTRIBUTES = .{
lib/std/os/windows.zig+56-24
......@@ -1080,6 +1080,9 @@ pub const CTL_CODE = packed struct(ULONG) {
10801080};
10811081
10821082pub const IOCTL = struct {
1083 pub const KSEC = struct {
1084 pub const GEN_RANDOM: CTL_CODE = .{ .DeviceType = .KSEC, .Function = 2, .Method = .BUFFERED, .Access = .ANY };
1085 };
10831086 pub const MOUNTMGR = struct {
10841087 pub const QUERY_POINTS: CTL_CODE = .{ .DeviceType = .MOUNTMGRCONTROLTYPE, .Function = 2, .Method = .BUFFERED, .Access = .ANY };
10851088 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
26442647 }
26452648}
26462649
2647pub const RtlGenRandomError = error{
2648 /// `RtlGenRandom` has been known to fail in situations where the system is under heavy load.
2649 /// Unfortunately, it does not call `SetLastError`, so it is not possible to get more specific
2650 /// error information; it could actually be due to an out-of-memory condition, for example.
2651 SystemResources,
2652};
2653
2654/// Call RtlGenRandom() instead of CryptGetRandom() on Windows
2655/// https://github.com/rust-lang-nursery/rand/issues/111
2656/// https://bugzilla.mozilla.org/show_bug.cgi?id=504270
2657pub fn RtlGenRandom(output: []u8) RtlGenRandomError!void {
2658 var total_read: usize = 0;
2659 var buff: []u8 = output[0..];
2660 const max_read_size: ULONG = maxInt(ULONG);
2661
2662 while (total_read < output.len) {
2663 const to_read: ULONG = @min(buff.len, max_read_size);
2664
2665 if (advapi32.RtlGenRandom(buff.ptr, to_read) == 0) {
2666 return error.SystemResources;
2667 }
2668
2669 total_read += to_read;
2670 buff = buff[to_read..];
2650/// An alternate implementation of ProcessPrng from bcryptprimitives.dll
2651/// This one has the following differences:
2652/// * does not heap allocate `buffer`
2653/// * does not introduce a dependency on bcryptprimitives.dll, which apparently
2654/// runs a test suite every time it is loaded
2655/// * reads buffer.len bytes from "\\Device\\CNG" rather than seeding a per-CPU
2656/// AES csprng with 48 bytes.
2657pub fn ProcessPrng(buffer: []u8) error{Unexpected}!void {
2658 const device_path = [_]u16{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'C', 'N', 'G' };
2659 var nt_name: UNICODE_STRING = .{
2660 .Length = device_path.len * 2,
2661 .MaximumLength = 0,
2662 .Buffer = @constCast(&device_path),
2663 };
2664 var cng_device: HANDLE = undefined;
2665 var io_status_block: IO_STATUS_BLOCK = undefined;
2666 switch (ntdll.NtOpenFile(
2667 &cng_device,
2668 .{
2669 .STANDARD = .{ .SYNCHRONIZE = true },
2670 .SPECIFIC = .{ .FILE = .{ .READ_DATA = true } },
2671 },
2672 &.{
2673 .Length = @sizeOf(OBJECT_ATTRIBUTES),
2674 .RootDirectory = null,
2675 .ObjectName = &nt_name,
2676 .Attributes = .{},
2677 .SecurityDescriptor = null,
2678 .SecurityQualityOfService = null,
2679 },
2680 &io_status_block,
2681 .VALID_FLAGS,
2682 .{ .IO = .SYNCHRONOUS_NONALERT },
2683 )) {
2684 .SUCCESS => {},
2685 .OBJECT_NAME_NOT_FOUND => return error.Unexpected, // Observed on wine 10.0
2686 else => |status| return unexpectedStatus(status),
2687 }
2688 defer _ = ntdll.NtClose(cng_device);
2689 switch (ntdll.NtDeviceIoControlFile(
2690 cng_device,
2691 null,
2692 null,
2693 null,
2694 &io_status_block,
2695 IOCTL.KSEC.GEN_RANDOM,
2696 null,
2697 0,
2698 buffer.ptr,
2699 @intCast(buffer.len),
2700 )) {
2701 .SUCCESS => {},
2702 else => |status| return unexpectedStatus(status),
26712703 }
26722704}
26732705
lib/std/os/windows/advapi32.zig-5
......@@ -28,11 +28,6 @@ pub extern "advapi32" fn RegQueryValueExW(
2828
2929pub extern "advapi32" fn RegCloseKey(hKey: HKEY) callconv(.winapi) LSTATUS;
3030
31// RtlGenRandom is known as SystemFunction036 under advapi32
32// http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx */
33pub extern "advapi32" fn SystemFunction036(output: [*]u8, length: ULONG) callconv(.winapi) BOOL;
34pub const RtlGenRandom = SystemFunction036;
35
3631pub const RRF = struct {
3732 pub const RT_ANY: DWORD = 0x0000ffff;
3833
lib/std/posix.zig+1-1
......@@ -370,7 +370,7 @@ pub const GetRandomError = OpenError;
370370/// library implementation.
371371pub fn getrandom(buffer: []u8) GetRandomError!void {
372372 if (native_os == .windows) {
373 return windows.RtlGenRandom(buffer);
373 return windows.ProcessPrng(buffer);
374374 }
375375 if (builtin.link_libc and @TypeOf(system.arc4random_buf) != void) {
376376 system.arc4random_buf(buffer.ptr, buffer.len);