// 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 RtlGenRandom API.
// On Wasm, Reader uses the Web Crypto API.
var Reader io.Reader
func Read(b []byte) (n int, err error) {
return io.ReadFull(Reader, b)
}
-
-func warnBlocked() {
- println("crypto/rand: blocked for 60 seconds waiting to read random data from the kernel")
-}
// urandom-style randomness.
var altGetRandom func([]byte) (ok bool)
+func warnBlocked() {
+ println("crypto/rand: blocked for 60 seconds waiting to read random data from the kernel")
+}
+
func (r *devReader) Read(b []byte) (n int, err error) {
if atomic.CompareAndSwapInt32(&r.used, 0, 1) {
// First use of randomness. Start timer to warn about
import (
"os"
- "sync"
- "sync/atomic"
"syscall"
- "time"
)
-// Implemented by using Windows CryptoAPI 2.0.
-
func init() { Reader = &rngReader{} }
-// A rngReader satisfies reads by reading from the Windows CryptGenRandom API.
-type rngReader struct {
- used int32 // atomic; whether this rngReader has been used
- prov syscall.Handle
- mu sync.Mutex
-}
+type rngReader struct{}
func (r *rngReader) Read(b []byte) (n int, err error) {
- if atomic.CompareAndSwapInt32(&r.used, 0, 1) {
- // First use of randomness. Start timer to warn about
- // being blocked on entropy not being available.
- t := time.AfterFunc(60*time.Second, warnBlocked)
- defer t.Stop()
- }
- 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)
- if err != nil {
- r.mu.Unlock()
- return 0, os.NewSyscallError("CryptAcquireContext", err)
- }
- }
- r.mu.Unlock()
+ // RtlGenRandom only accepts 2**32-1 bytes at a time, so truncate.
+ inputLen := uint32(len(b))
- if len(b) == 0 {
+ if inputLen == 0 {
return 0, nil
}
- err = syscall.CryptGenRandom(r.prov, uint32(len(b)), &b[0])
+
+ err = syscall.RtlGenRandom(&b[0], inputLen)
if err != nil {
- return 0, os.NewSyscallError("CryptGenRandom", err)
+ return 0, os.NewSyscallError("RtlGenRandom", err)
}
- return len(b), nil
+ return int(inputLen), nil
}
//sys CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (err error) = advapi32.CryptAcquireContextW
//sys CryptReleaseContext(provhandle Handle, flags uint32) (err error) = advapi32.CryptReleaseContext
//sys CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (err error) = advapi32.CryptGenRandom
+//sys RtlGenRandom(buf *uint8, bytes uint32) (err error) = advapi32.SystemFunction036
//sys GetEnvironmentStrings() (envs *uint16, err error) [failretval==nil] = kernel32.GetEnvironmentStringsW
//sys FreeEnvironmentStrings(envs *uint16) (err error) = kernel32.FreeEnvironmentStringsW
//sys GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, err error) = kernel32.GetEnvironmentVariableW
procCryptAcquireContextW = modadvapi32.NewProc("CryptAcquireContextW")
procCryptReleaseContext = modadvapi32.NewProc("CryptReleaseContext")
procCryptGenRandom = modadvapi32.NewProc("CryptGenRandom")
+ procSystemFunction036 = modadvapi32.NewProc("SystemFunction036")
procGetEnvironmentStringsW = modkernel32.NewProc("GetEnvironmentStringsW")
procFreeEnvironmentStringsW = modkernel32.NewProc("FreeEnvironmentStringsW")
procGetEnvironmentVariableW = modkernel32.NewProc("GetEnvironmentVariableW")
return
}
+func RtlGenRandom(buf *uint8, bytes uint32) (err error) {
+ r1, _, e1 := Syscall(procSystemFunction036.Addr(), 2, uintptr(unsafe.Pointer(buf)), uintptr(bytes), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
func GetEnvironmentStrings() (envs *uint16, err error) {
r0, _, e1 := Syscall(procGetEnvironmentStringsW.Addr(), 0, 0, 0, 0)
envs = (*uint16)(unsafe.Pointer(r0))