summaryrefslogtreecommitdiff
path: root/libgo/go/crypto/rand
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/crypto/rand')
-rw-r--r--libgo/go/crypto/rand/rand.go6
-rw-r--r--libgo/go/crypto/rand/rand_batched.go42
-rw-r--r--libgo/go/crypto/rand/rand_batched_test.go (renamed from libgo/go/crypto/rand/rand_linux_test.go)2
-rw-r--r--libgo/go/crypto/rand/rand_freebsd.go9
-rw-r--r--libgo/go/crypto/rand/rand_linux.go34
-rw-r--r--libgo/go/crypto/rand/rand_unix.go18
-rw-r--r--libgo/go/crypto/rand/rand_windows.go9
7 files changed, 77 insertions, 43 deletions
diff --git a/libgo/go/crypto/rand/rand.go b/libgo/go/crypto/rand/rand.go
index b8df8a37117..a5ccd19de32 100644
--- a/libgo/go/crypto/rand/rand.go
+++ b/libgo/go/crypto/rand/rand.go
@@ -11,7 +11,7 @@ import "io"
// Reader is a global, shared instance of a cryptographically
// secure random number generator.
//
-// On Linux, Reader uses getrandom(2) if available, /dev/urandom otherwise.
+// 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.
@@ -23,3 +23,7 @@ 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")
+}
diff --git a/libgo/go/crypto/rand/rand_batched.go b/libgo/go/crypto/rand/rand_batched.go
new file mode 100644
index 00000000000..60267fd4bc2
--- /dev/null
+++ b/libgo/go/crypto/rand/rand_batched.go
@@ -0,0 +1,42 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux freebsd
+
+package rand
+
+import (
+ "internal/syscall/unix"
+)
+
+// maxGetRandomRead is platform dependent.
+func init() {
+ altGetRandom = batched(getRandomBatch, maxGetRandomRead)
+}
+
+// batched returns a function that calls f to populate a []byte by chunking it
+// into subslices of, at most, readMax bytes.
+func batched(f func([]byte) bool, readMax int) func([]byte) bool {
+ return func(buf []byte) bool {
+ for len(buf) > readMax {
+ if !f(buf[:readMax]) {
+ return false
+ }
+ buf = buf[readMax:]
+ }
+ return len(buf) == 0 || f(buf)
+ }
+}
+
+// If the kernel is too old to support the getrandom syscall(),
+// unix.GetRandom will immediately return ENOSYS and we will then fall back to
+// reading from /dev/urandom in rand_unix.go. unix.GetRandom caches the ENOSYS
+// result so we only suffer the syscall overhead once in this case.
+// If the kernel supports the getrandom() syscall, unix.GetRandom will block
+// until the kernel has sufficient randomness (as we don't use GRND_NONBLOCK).
+// In this case, unix.GetRandom will not return an error.
+func getRandomBatch(p []byte) (ok bool) {
+ n, err := unix.GetRandom(p, 0)
+ return n == len(p) && err == nil
+}
diff --git a/libgo/go/crypto/rand/rand_linux_test.go b/libgo/go/crypto/rand/rand_batched_test.go
index 77b7b6ebd7a..837db83f770 100644
--- a/libgo/go/crypto/rand/rand_linux_test.go
+++ b/libgo/go/crypto/rand/rand_batched_test.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build linux freebsd
+
package rand
import (
diff --git a/libgo/go/crypto/rand/rand_freebsd.go b/libgo/go/crypto/rand/rand_freebsd.go
new file mode 100644
index 00000000000..75f683c386d
--- /dev/null
+++ b/libgo/go/crypto/rand/rand_freebsd.go
@@ -0,0 +1,9 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand
+
+// maxGetRandomRead is the maximum number of bytes to ask for in one call to the
+// getrandom() syscall. In FreeBSD at most 256 bytes will be returned per call.
+const maxGetRandomRead = 1 << 8
diff --git a/libgo/go/crypto/rand/rand_linux.go b/libgo/go/crypto/rand/rand_linux.go
index dbd038cc582..26b93c54d28 100644
--- a/libgo/go/crypto/rand/rand_linux.go
+++ b/libgo/go/crypto/rand/rand_linux.go
@@ -4,14 +4,6 @@
package rand
-import (
- "internal/syscall/unix"
-)
-
-func init() {
- altGetRandom = batched(getRandomLinux, maxGetRandomRead)
-}
-
// maxGetRandomRead is the maximum number of bytes to ask for in one call to the
// getrandom() syscall. In linux at most 2^25-1 bytes will be returned per call.
// From the manpage
@@ -20,29 +12,3 @@ func init() {
// is returned by a single call to getrandom() on systems where int
// has a size of 32 bits.
const maxGetRandomRead = (1 << 25) - 1
-
-// batched returns a function that calls f to populate a []byte by chunking it
-// into subslices of, at most, readMax bytes.
-func batched(f func([]byte) bool, readMax int) func([]byte) bool {
- return func(buf []byte) bool {
- for len(buf) > readMax {
- if !f(buf[:readMax]) {
- return false
- }
- buf = buf[readMax:]
- }
- return len(buf) == 0 || f(buf)
- }
-}
-
-// If the kernel is too old (before 3.17) to support the getrandom syscall(),
-// unix.GetRandom will immediately return ENOSYS and we will then fall back to
-// reading from /dev/urandom in rand_unix.go. unix.GetRandom caches the ENOSYS
-// result so we only suffer the syscall overhead once in this case.
-// If the kernel supports the getrandom() syscall, unix.GetRandom will block
-// until the kernel has sufficient randomness (as we don't use GRND_NONBLOCK).
-// In this case, unix.GetRandom will not return an error.
-func getRandomLinux(p []byte) (ok bool) {
- n, err := unix.GetRandom(p, 0)
- return n == len(p) && err == nil
-}
diff --git a/libgo/go/crypto/rand/rand_unix.go b/libgo/go/crypto/rand/rand_unix.go
index ec474d36ccf..f3091f51c5f 100644
--- a/libgo/go/crypto/rand/rand_unix.go
+++ b/libgo/go/crypto/rand/rand_unix.go
@@ -13,10 +13,12 @@ import (
"bufio"
"crypto/aes"
"crypto/cipher"
+ "encoding/binary"
"io"
"os"
"runtime"
"sync"
+ "sync/atomic"
"time"
)
@@ -38,6 +40,7 @@ type devReader struct {
name string
f io.Reader
mu sync.Mutex
+ used int32 // atomic; whether this devReader has been used
}
// altGetRandom if non-nil specifies an OS-specific function to get
@@ -45,6 +48,12 @@ type devReader struct {
var altGetRandom func([]byte) (ok bool)
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
+ // being blocked on entropy not being available.
+ t := time.AfterFunc(60*time.Second, warnBlocked)
+ defer t.Stop()
+ }
if altGetRandom != nil && r.name == urandomDevice && altGetRandom(b) {
return len(b), nil
}
@@ -137,14 +146,7 @@ func (r *reader) Read(b []byte) (n int, err error) {
// dst = encrypt(t^seed)
// seed = encrypt(t^dst)
ns := time.Now().UnixNano()
- r.time[0] = byte(ns >> 56)
- r.time[1] = byte(ns >> 48)
- r.time[2] = byte(ns >> 40)
- r.time[3] = byte(ns >> 32)
- r.time[4] = byte(ns >> 24)
- r.time[5] = byte(ns >> 16)
- r.time[6] = byte(ns >> 8)
- r.time[7] = byte(ns)
+ binary.BigEndian.PutUint64(r.time[:], uint64(ns))
r.cipher.Encrypt(r.time[0:], r.time[0:])
for i := 0; i < aes.BlockSize; i++ {
r.dst[i] = r.time[i] ^ r.seed[i]
diff --git a/libgo/go/crypto/rand/rand_windows.go b/libgo/go/crypto/rand/rand_windows.go
index 4d7511a8400..78a4ed6d67b 100644
--- a/libgo/go/crypto/rand/rand_windows.go
+++ b/libgo/go/crypto/rand/rand_windows.go
@@ -10,7 +10,9 @@ package rand
import (
"os"
"sync"
+ "sync/atomic"
"syscall"
+ "time"
)
// Implemented by using Windows CryptoAPI 2.0.
@@ -19,11 +21,18 @@ 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
}
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