Skip to content

Commit c7fb621

Browse files
committed
crypto/rand: use BCryptGenRandom instead of CryptGenRandom on Windows
The existing function that is used is CryptGenRandom. This function and the whole underling API is deprecated. Use the function BCryptGenRandom from the new recommended API called "Cryptography API: Next Generation (CNG)". Preload and use the BCRYPT_RNG_ALGORITHM provider. It follows the standards: FIPS 186-2, FIPS 140-2, NIST SP 800-90 Fixes #33542
1 parent 5cc030a commit c7fb621

File tree

4 files changed

+38
-9
lines changed

4 files changed

+38
-9
lines changed

src/crypto/rand/rand.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import "io"
1414
// On Linux and FreeBSD, Reader uses getrandom(2) if available, /dev/urandom otherwise.
1515
// On OpenBSD, Reader uses getentropy(2).
1616
// On other Unix-like systems, Reader reads from /dev/urandom.
17-
// On Windows systems, Reader uses the CryptGenRandom API.
17+
// On Windows systems, Reader uses the BCryptGenRandom API with provider BCRYPT_RNG_ALGORITHM.
1818
// On Wasm, Reader uses the Web Crypto API.
1919
var Reader io.Reader
2020

src/crypto/rand/rand_windows.go

+15-8
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
package rand
99

1010
import (
11+
"internal/syscall/windows"
1112
"os"
1213
"sync"
1314
"sync/atomic"
@@ -35,22 +36,28 @@ func (r *rngReader) Read(b []byte) (n int, err error) {
3536
}
3637
r.mu.Lock()
3738
if r.prov == 0 {
38-
const provType = syscall.PROV_RSA_FULL
39-
const flags = syscall.CRYPT_VERIFYCONTEXT | syscall.CRYPT_SILENT
40-
err := syscall.CryptAcquireContext(&r.prov, nil, nil, provType, flags)
39+
// BCRYPT_RNG_ALGORITHM is defined here:
40+
// https://docs.microsoft.com/en-us/windows/win32/seccng/cng-algorithm-identifiers
41+
// Standard: FIPS 186-2, FIPS 140-2, NIST SP 800-90
42+
algID, err := syscall.UTF16PtrFromString(windows.BCRYPT_RNG_ALGORITHM)
4143
if err != nil {
4244
r.mu.Unlock()
43-
return 0, os.NewSyscallError("CryptAcquireContext", err)
45+
return 0, err
46+
}
47+
status := windows.BCryptOpenAlgorithmProvider(&r.prov, algID, nil, 0)
48+
if status != 0 {
49+
r.mu.Unlock()
50+
return 0, os.NewSyscallError("BCryptOpenAlgorithmProvider", syscall.Errno(status))
4451
}
4552
}
4653
r.mu.Unlock()
4754

4855
if len(b) == 0 {
4956
return 0, nil
5057
}
51-
err = syscall.CryptGenRandom(r.prov, uint32(len(b)), &b[0])
52-
if err != nil {
53-
return 0, os.NewSyscallError("CryptGenRandom", err)
58+
status := windows.BCryptGenRandom(r.prov, &b[0], uint32(len(b)), 0)
59+
if status != 0 {
60+
return 0, os.NewSyscallError("BCryptGenRandom", syscall.Errno(status))
5461
}
55-
return len(b), nil
62+
return int(uint32(len(b))), nil
5663
}

src/internal/syscall/windows/syscall_windows.go

+7
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,13 @@ const (
145145
//sys GetComputerNameEx(nameformat uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW
146146
//sys MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) = MoveFileExW
147147
//sys GetModuleFileName(module syscall.Handle, fn *uint16, len uint32) (n uint32, err error) = kernel32.GetModuleFileNameW
148+
//sys BCryptOpenAlgorithmProvider(algHandle *syscall.Handle, algID *uint16, impl *uint16, flags uint32) (status int32) = bcrypt.BCryptOpenAlgorithmProvider
149+
//sys BCryptGenRandom(algHandle syscall.Handle, buf *byte, buflen uint32, flags uint32) (status int32) = bcrypt.BCryptGenRandom
150+
151+
const (
152+
// bcrypt.h
153+
BCRYPT_RNG_ALGORITHM = "RNG"
154+
)
148155

149156
const (
150157
WSA_FLAG_OVERLAPPED = 0x01

src/internal/syscall/windows/zsyscall_windows.go

+15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)