diff --git a/src/crypto/rand/rand.go b/src/crypto/rand/rand.go index a5ccd19de32994..6127d60a4f7ab3 100644 --- a/src/crypto/rand/rand.go +++ b/src/crypto/rand/rand.go @@ -14,7 +14,7 @@ import "io" // On Linux and FreeBSD, Reader uses getrandom(2) if available, /dev/urandom otherwise. // On OpenBSD, Reader uses getentropy(2). // On other Unix-like systems, Reader reads from /dev/urandom. -// On Windows systems, Reader uses the CryptGenRandom API. +// On Windows systems, Reader uses the BCryptGenRandom API with provider BCRYPT_RNG_ALGORITHM. // On Wasm, Reader uses the Web Crypto API. var Reader io.Reader diff --git a/src/crypto/rand/rand_windows.go b/src/crypto/rand/rand_windows.go index 78a4ed6d67b5c8..8509e5f0317758 100644 --- a/src/crypto/rand/rand_windows.go +++ b/src/crypto/rand/rand_windows.go @@ -8,6 +8,7 @@ package rand import ( + "internal/syscall/windows" "os" "sync" "sync/atomic" @@ -35,12 +36,18 @@ func (r *rngReader) Read(b []byte) (n int, err error) { } r.mu.Lock() if r.prov == 0 { - const provType = syscall.PROV_RSA_FULL - const flags = syscall.CRYPT_VERIFYCONTEXT | syscall.CRYPT_SILENT - err := syscall.CryptAcquireContext(&r.prov, nil, nil, provType, flags) + // BCRYPT_RNG_ALGORITHM is defined here: + // https://docs.microsoft.com/en-us/windows/win32/seccng/cng-algorithm-identifiers + // Standard: FIPS 186-2, FIPS 140-2, NIST SP 800-90 + algID, err := syscall.UTF16PtrFromString(windows.BCRYPT_RNG_ALGORITHM) if err != nil { r.mu.Unlock() - return 0, os.NewSyscallError("CryptAcquireContext", err) + return 0, err + } + status := windows.BCryptOpenAlgorithmProvider(&r.prov, algID, nil, 0) + if status != 0 { + r.mu.Unlock() + return 0, os.NewSyscallError("BCryptOpenAlgorithmProvider", syscall.Errno(status)) } } r.mu.Unlock() @@ -48,9 +55,9 @@ func (r *rngReader) Read(b []byte) (n int, err error) { if len(b) == 0 { return 0, nil } - err = syscall.CryptGenRandom(r.prov, uint32(len(b)), &b[0]) - if err != nil { - return 0, os.NewSyscallError("CryptGenRandom", err) + status := windows.BCryptGenRandom(r.prov, &b[0], uint32(len(b)), 0) + if status != 0 { + return 0, os.NewSyscallError("BCryptGenRandom", syscall.Errno(status)) } - return len(b), nil + return int(uint32(len(b))), nil } diff --git a/src/internal/syscall/windows/syscall_windows.go b/src/internal/syscall/windows/syscall_windows.go index edf0b5a40b8a28..23e0498ff7d57d 100644 --- a/src/internal/syscall/windows/syscall_windows.go +++ b/src/internal/syscall/windows/syscall_windows.go @@ -145,6 +145,13 @@ const ( //sys GetComputerNameEx(nameformat uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW //sys MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) = MoveFileExW //sys GetModuleFileName(module syscall.Handle, fn *uint16, len uint32) (n uint32, err error) = kernel32.GetModuleFileNameW +//sys BCryptOpenAlgorithmProvider(algHandle *syscall.Handle, algID *uint16, impl *uint16, flags uint32) (status int32) = bcrypt.BCryptOpenAlgorithmProvider +//sys BCryptGenRandom(algHandle syscall.Handle, buf *byte, buflen uint32, flags uint32) (status int32) = bcrypt.BCryptGenRandom + +const ( + // bcrypt.h + BCRYPT_RNG_ALGORITHM = "RNG" +) const ( WSA_FLAG_OVERLAPPED = 0x01 diff --git a/src/internal/syscall/windows/zsyscall_windows.go b/src/internal/syscall/windows/zsyscall_windows.go index ca5b4e6f16ddb3..1bc9d3bfdfb587 100644 --- a/src/internal/syscall/windows/zsyscall_windows.go +++ b/src/internal/syscall/windows/zsyscall_windows.go @@ -38,6 +38,7 @@ func errnoErr(e syscall.Errno) error { var ( modiphlpapi = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll")) modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll")) + modbcrypt = syscall.NewLazyDLL(sysdll.Add("bcrypt.dll")) modws2_32 = syscall.NewLazyDLL(sysdll.Add("ws2_32.dll")) modnetapi32 = syscall.NewLazyDLL(sysdll.Add("netapi32.dll")) modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll")) @@ -48,6 +49,8 @@ var ( procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW") procMoveFileExW = modkernel32.NewProc("MoveFileExW") procGetModuleFileNameW = modkernel32.NewProc("GetModuleFileNameW") + procBCryptOpenAlgorithmProvider = modbcrypt.NewProc("BCryptOpenAlgorithmProvider") + procBCryptGenRandom = modbcrypt.NewProc("BCryptGenRandom") procWSASocketW = modws2_32.NewProc("WSASocketW") procLockFileEx = modkernel32.NewProc("LockFileEx") procUnlockFileEx = modkernel32.NewProc("UnlockFileEx") @@ -118,6 +121,18 @@ func GetModuleFileName(module syscall.Handle, fn *uint16, len uint32) (n uint32, return } +func BCryptOpenAlgorithmProvider(algHandle *syscall.Handle, algID *uint16, impl *uint16, flags uint32) (status int32) { + r0, _, _ := syscall.Syscall6(procBCryptOpenAlgorithmProvider.Addr(), 4, uintptr(unsafe.Pointer(algHandle)), uintptr(unsafe.Pointer(algID)), uintptr(unsafe.Pointer(impl)), uintptr(flags), 0, 0) + status = int32(r0) + return +} + +func BCryptGenRandom(algHandle syscall.Handle, buf *byte, buflen uint32, flags uint32) (status int32) { + r0, _, _ := syscall.Syscall6(procBCryptGenRandom.Addr(), 4, uintptr(algHandle), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(flags), 0, 0) + status = int32(r0) + return +} + func WSASocket(af int32, typ int32, protocol int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (handle syscall.Handle, err error) { r0, _, e1 := syscall.Syscall6(procWSASocketW.Addr(), 6, uintptr(af), uintptr(typ), uintptr(protocol), uintptr(unsafe.Pointer(protinfo)), uintptr(group), uintptr(flags)) handle = syscall.Handle(r0)