crypto/rand: properly handle large Read on windows

Use the batched reader to chunk large Read calls on windows to a max of
1 << 31 - 1 bytes. This prevents an infinite loop when trying to read
more than 1 << 32 -1 bytes, due to how RtlGenRandom works.

This change moves the batched function from rand_unix.go to rand.go,
since it is now needed for both windows and unix implementations.

Fixes #52561

Change-Id: Id98fc4b1427e5cb2132762a445b2aed646a37473
Reviewed-on: https://go-review.googlesource.com/c/go/+/402257
Run-TryBot: Roland Shoemaker <roland@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Filippo Valsorda <valsorda@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/src/crypto/rand/rand_windows.go b/src/crypto/rand/rand_windows.go
index 7379f14..6c0655c 100644
--- a/src/crypto/rand/rand_windows.go
+++ b/src/crypto/rand/rand_windows.go
@@ -9,7 +9,6 @@
 
 import (
 	"internal/syscall/windows"
-	"os"
 )
 
 func init() { Reader = &rngReader{} }
@@ -17,16 +16,11 @@
 type rngReader struct{}
 
 func (r *rngReader) Read(b []byte) (n int, err error) {
-	// RtlGenRandom only accepts 2**32-1 bytes at a time, so truncate.
-	inputLen := uint32(len(b))
-
-	if inputLen == 0 {
-		return 0, nil
+	// RtlGenRandom only returns 1<<32-1 bytes at a time. We only read at
+	// most 1<<31-1 bytes at a time so that  this works the same on 32-bit
+	// and 64-bit systems.
+	if err := batched(windows.RtlGenRandom, 1<<31-1)(b); err != nil {
+		return 0, err
 	}
-
-	err = windows.RtlGenRandom(b)
-	if err != nil {
-		return 0, os.NewSyscallError("RtlGenRandom", err)
-	}
-	return int(inputLen), nil
+	return len(b), nil
 }