| ... | ... | @@ -1080,6 +1080,9 @@ pub const CTL_CODE = packed struct(ULONG) { |
| 1080 | 1080 | }; |
| 1081 | 1081 | |
| 1082 | 1082 | pub const IOCTL = struct { |
| 1083 | pub const KSEC = struct { |
| 1084 | pub const GEN_RANDOM: CTL_CODE = .{ .DeviceType = .KSEC, .Function = 2, .Method = .BUFFERED, .Access = .ANY }; |
| 1085 | }; |
| 1083 | 1086 | pub const MOUNTMGR = struct { |
| 1084 | 1087 | pub const QUERY_POINTS: CTL_CODE = .{ .DeviceType = .MOUNTMGRCONTROLTYPE, .Function = 2, .Method = .BUFFERED, .Access = .ANY }; |
| 1085 | 1088 | 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 |
| 2644 | 2647 | } |
| 2645 | 2648 | } |
| 2646 | 2649 | |
| 2647 | | pub 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 |
| 2657 | | pub 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. |
| 2657 | pub 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), |
| 2671 | 2703 | } |
| 2672 | 2704 | } |
| 2673 | 2705 | |