From 88f6563c80dfe5b0039aae130e82129c6e37c489 Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Fri, 8 May 2020 02:01:05 +0300 Subject: [PATCH] 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 #33542 --- src/crypto/rand/rand.go | 2 +- src/crypto/rand/rand_windows.go | 39 +++++---------------------------- src/syscall/syscall_windows.go | 1 + src/syscall/types_windows.go | 3 +++ src/syscall/zsyscall_windows.go | 36 ++++++++++++++++++++---------- 5 files changed, 35 insertions(+), 46 deletions(-) diff --git a/src/crypto/rand/rand.go b/src/crypto/rand/rand.go index a5ccd19de32994..107e154494c742 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. // 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..3088f2db1169cf 100644 --- a/src/crypto/rand/rand_windows.go +++ b/src/crypto/rand/rand_windows.go @@ -9,48 +9,19 @@ package rand import ( "os" - "sync" - "sync/atomic" "syscall" - "time" ) -// Implemented by using Windows CryptoAPI 2.0. +// Implemented by using the Cryptography Next Generation (CNG) API. 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() - - if len(b) == 0 { - return 0, nil - } - err = syscall.CryptGenRandom(r.prov, uint32(len(b)), &b[0]) + err = syscall.BCryptGenRandom(nil, &b[0], uint32(len(b)), syscall.BCRYPT_USE_SYSTEM_PREFERRED_RNG) if err != nil { - return 0, os.NewSyscallError("CryptGenRandom", err) + return 0, os.NewSyscallError("BCryptGenRandom", err) } - return len(b), nil + return int(uint32(len(b))), nil } diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go index 89c0a930cb6b93..3ff323940861c4 100644 --- a/src/syscall/syscall_windows.go +++ b/src/syscall/syscall_windows.go @@ -234,6 +234,7 @@ func NewCallbackCDecl(fn interface{}) uintptr { //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 BCryptGenRandom(algorithmhandle Handle, buf *uint8, buflen uint32, flags uint32) (err error) = bcrypt.BCryptGenRandom //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 diff --git a/src/syscall/types_windows.go b/src/syscall/types_windows.go index 0349f3b180dea0..2f5b906fe2dbdc 100644 --- a/src/syscall/types_windows.go +++ b/src/syscall/types_windows.go @@ -241,6 +241,9 @@ const ( CRYPT_SILENT = 0x00000040 CRYPT_DEFAULT_CONTAINER_OPTIONAL = 0x00000080 + // bcrypt.h + BCRYPT_USE_SYSTEM_PREFERRED_RNG = 0x00000002 + USAGE_MATCH_TYPE_AND = 0 USAGE_MATCH_TYPE_OR = 1 diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go index 2348f6534f7af7..be54bd16f1d825 100644 --- a/src/syscall/zsyscall_windows.go +++ b/src/syscall/zsyscall_windows.go @@ -35,17 +35,18 @@ func errnoErr(e Errno) error { } var ( - modkernel32 = NewLazyDLL(sysdll.Add("kernel32.dll")) - modadvapi32 = NewLazyDLL(sysdll.Add("advapi32.dll")) - modshell32 = NewLazyDLL(sysdll.Add("shell32.dll")) - modmswsock = NewLazyDLL(sysdll.Add("mswsock.dll")) - modcrypt32 = NewLazyDLL(sysdll.Add("crypt32.dll")) - modws2_32 = NewLazyDLL(sysdll.Add("ws2_32.dll")) - moddnsapi = NewLazyDLL(sysdll.Add("dnsapi.dll")) - modiphlpapi = NewLazyDLL(sysdll.Add("iphlpapi.dll")) - modsecur32 = NewLazyDLL(sysdll.Add("secur32.dll")) - modnetapi32 = NewLazyDLL(sysdll.Add("netapi32.dll")) - moduserenv = NewLazyDLL(sysdll.Add("userenv.dll")) + modkernel32 = NewLazyDLL(sysdll.Add("kernel32.dll") + modadvapi32 = NewLazyDLL(sysdll.Add("advapi32.dll") + modbcrypt = NewLazyDLL(sysdll.Add("bcrypt.dll") + modshell32 = NewLazyDLL(sysdll.Add("shell32.dll") + modmswsock = NewLazyDLL(sysdll.Add("mswsock.dll") + modcrypt32 = NewLazyDLL(sysdll.Add("crypt32.dll") + modws2_32 = NewLazyDLL(sysdll.Add("ws2_32.dll") + moddnsapi = NewLazyDLL(sysdll.Add("dnsapi.dll") + modiphlpapi = NewLazyDLL(sysdll.Add("iphlpapi.dll") + modsecur32 = NewLazyDLL(sysdll.Add("secur32.dll") + modnetapi32 = NewLazyDLL(sysdll.Add("netapi32.dll") + moduserenv = NewLazyDLL(sysdll.Add("userenv.dll") procGetLastError = modkernel32.NewProc("GetLastError") procLoadLibraryW = modkernel32.NewProc("LoadLibraryW") @@ -95,6 +96,7 @@ var ( procCryptAcquireContextW = modadvapi32.NewProc("CryptAcquireContextW") procCryptReleaseContext = modadvapi32.NewProc("CryptReleaseContext") procCryptGenRandom = modadvapi32.NewProc("CryptGenRandom") + procBCryptGenRandom = modbcrypt.NewProc("BCryptGenRandom") procGetEnvironmentStringsW = modkernel32.NewProc("GetEnvironmentStringsW") procFreeEnvironmentStringsW = modkernel32.NewProc("FreeEnvironmentStringsW") procGetEnvironmentVariableW = modkernel32.NewProc("GetEnvironmentVariableW") @@ -821,6 +823,18 @@ func CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (err error) { return } +func BCryptGenRandom(algorithmhandle Handle, buf *uint8, buflen uint32, flags uint32) (err error) { + r1, _, e1 := Syscall6(procBCryptGenRandom.Addr(), 4, uintptr(algorithmhandle), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(flags), 0, 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))