Skip to content

Commit 333e904

Browse files
committed
crypto/rand: generate random numbers using RtlGenRandom on Windows
CryptGenRandom appears to be unfavorable these days, whereas the classic RtlGenRandom is still going strong. This commit also moves the warnBlocked function into rand_unix, rather than rand, because it's now only used on unix. Fixes #33542 Change-Id: I5c02a5917572f54079d627972401efb6e1ce4057 Reviewed-on: https://go-review.googlesource.com/c/go/+/210057 Run-TryBot: Jason A. Donenfeld <Jason@zx2c4.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Filippo Valsorda <filippo@golang.org> Trust: Jason A. Donenfeld <Jason@zx2c4.com>
1 parent 8a01323 commit 333e904

File tree

5 files changed

+27
-37
lines changed

5 files changed

+27
-37
lines changed

src/crypto/rand/rand.go

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

@@ -23,7 +23,3 @@ var Reader io.Reader
2323
func Read(b []byte) (n int, err error) {
2424
return io.ReadFull(Reader, b)
2525
}
26-
27-
func warnBlocked() {
28-
println("crypto/rand: blocked for 60 seconds waiting to read random data from the kernel")
29-
}

src/crypto/rand/rand_unix.go

+4
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ type devReader struct {
4747
// urandom-style randomness.
4848
var altGetRandom func([]byte) (ok bool)
4949

50+
func warnBlocked() {
51+
println("crypto/rand: blocked for 60 seconds waiting to read random data from the kernel")
52+
}
53+
5054
func (r *devReader) Read(b []byte) (n int, err error) {
5155
if atomic.CompareAndSwapInt32(&r.used, 0, 1) {
5256
// First use of randomness. Start timer to warn about

src/crypto/rand/rand_windows.go

+8-32
Original file line numberDiff line numberDiff line change
@@ -9,48 +9,24 @@ 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.
19-
2015
func init() { Reader = &rngReader{} }
2116

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-
}
17+
type rngReader struct{}
2818

2919
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()
20+
// RtlGenRandom only accepts 2**32-1 bytes at a time, so truncate.
21+
inputLen := uint32(len(b))
4722

48-
if len(b) == 0 {
23+
if inputLen == 0 {
4924
return 0, nil
5025
}
51-
err = syscall.CryptGenRandom(r.prov, uint32(len(b)), &b[0])
26+
27+
err = syscall.RtlGenRandom(&b[0], inputLen)
5228
if err != nil {
53-
return 0, os.NewSyscallError("CryptGenRandom", err)
29+
return 0, os.NewSyscallError("RtlGenRandom", err)
5430
}
55-
return len(b), nil
31+
return int(inputLen), nil
5632
}

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 RtlGenRandom(buf *uint8, bytes uint32) (err error) = advapi32.SystemFunction036
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/zsyscall_windows.go

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

0 commit comments

Comments
 (0)