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)