Skip to content

Commit ddc7dea

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)". Fixes golang#33542
1 parent 4fda7dc commit ddc7dea

File tree

5 files changed

+26
-32
lines changed

5 files changed

+26
-32
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.
1818
// On Wasm, Reader uses the Web Crypto API.
1919
var Reader io.Reader
2020

src/crypto/rand/rand_windows.go

+5-31
Original file line numberDiff line numberDiff line change
@@ -9,48 +9,22 @@ package rand
99

1010
import (
1111
"os"
12-
"sync"
13-
"sync/atomic"
1412
"syscall"
15-
"time"
1613
)
1714

18-
// Implemented by using Windows CryptoAPI 2.0.
15+
// Implemented by using the Cryptography Next Generation (CNG) API.
1916

2017
func init() { Reader = &rngReader{} }
2118

22-
// A rngReader satisfies reads by reading from the Windows CryptGenRandom API.
23-
type rngReader struct {
24-
used int32 // atomic; whether this rngReader has been used
25-
prov syscall.Handle
26-
mu sync.Mutex
27-
}
19+
type rngReader struct{}
2820

2921
func (r *rngReader) Read(b []byte) (n int, err error) {
30-
if atomic.CompareAndSwapInt32(&r.used, 0, 1) {
31-
// First use of randomness. Start timer to warn about
32-
// being blocked on entropy not being available.
33-
t := time.AfterFunc(60*time.Second, warnBlocked)
34-
defer t.Stop()
35-
}
36-
r.mu.Lock()
37-
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)
41-
if err != nil {
42-
r.mu.Unlock()
43-
return 0, os.NewSyscallError("CryptAcquireContext", err)
44-
}
45-
}
46-
r.mu.Unlock()
47-
4822
if len(b) == 0 {
4923
return 0, nil
5024
}
51-
err = syscall.CryptGenRandom(r.prov, uint32(len(b)), &b[0])
25+
err = syscall.BCryptGenRandom(0, &b[0], uint32(len(b)), syscall.BCRYPT_USE_SYSTEM_PREFERRED_RNG)
5226
if err != nil {
53-
return 0, os.NewSyscallError("CryptGenRandom", err)
27+
return 0, os.NewSyscallError("BCryptGenRandom", err)
5428
}
55-
return len(b), nil
29+
return int(uint32(len(b))), nil
5630
}

src/syscall/syscall_windows.go

+1
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
234234
//sys CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (err error) = advapi32.CryptAcquireContextW
235235
//sys CryptReleaseContext(provhandle Handle, flags uint32) (err error) = advapi32.CryptReleaseContext
236236
//sys CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (err error) = advapi32.CryptGenRandom
237+
//sys BCryptGenRandom(algorithmhandle Handle, buf *byte, buflen uint32, flags uint32) (err error) [failretval!=0] = bcrypt.BCryptGenRandom
237238
//sys GetEnvironmentStrings() (envs *uint16, err error) [failretval==nil] = kernel32.GetEnvironmentStringsW
238239
//sys FreeEnvironmentStrings(envs *uint16) (err error) = kernel32.FreeEnvironmentStringsW
239240
//sys GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, err error) = kernel32.GetEnvironmentVariableW

src/syscall/types_windows.go

+5
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,11 @@ const (
214214
FILE_ACTION_RENAMED_NEW_NAME
215215
)
216216

217+
const (
218+
// bcrypt.h
219+
BCRYPT_USE_SYSTEM_PREFERRED_RNG = 0x00000002
220+
)
221+
217222
const (
218223
// wincrypt.h
219224
PROV_RSA_FULL = 1

src/syscall/zsyscall_windows.go

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

0 commit comments

Comments
 (0)