mirror of https://github.com/golang/go.git
[dev.boringcrypto] all: merge master into dev.boringcrypto
Change-Id: I30dbbe508a6252d50b4154cb9a8299cf0a054449
This commit is contained in:
commit
19e4b10f2f
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
//go:build unix
|
||||||
|
|
||||||
package rand
|
package rand
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,11 @@
|
||||||
package rand
|
package rand
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
@ -35,7 +35,7 @@ func init() {
|
||||||
type reader struct {
|
type reader struct {
|
||||||
f io.Reader
|
f io.Reader
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
used bool // whether this reader has been used
|
used uint32 // Atomic: 0 - never used, 1 - used, but f == nil, 2 - used, and f != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// altGetRandom if non-nil specifies an OS-specific function to get
|
// altGetRandom if non-nil specifies an OS-specific function to get
|
||||||
|
|
@ -43,24 +43,11 @@ type reader struct {
|
||||||
var altGetRandom func([]byte) (ok bool)
|
var altGetRandom func([]byte) (ok bool)
|
||||||
|
|
||||||
// batched returns a function that calls f to populate a []byte by chunking it
|
// batched returns a function that calls f to populate a []byte by chunking it
|
||||||
// into subslices of, at most, readMax bytes, buffering min(readMax, 4096)
|
// into subslices of, at most, readMax bytes.
|
||||||
// bytes at a time.
|
|
||||||
func batched(f func([]byte) error, readMax int) func([]byte) bool {
|
func batched(f func([]byte) error, readMax int) func([]byte) bool {
|
||||||
bufferSize := 4096
|
|
||||||
if bufferSize > readMax {
|
|
||||||
bufferSize = readMax
|
|
||||||
}
|
|
||||||
fullBuffer := make([]byte, bufferSize)
|
|
||||||
var buf []byte
|
|
||||||
return func(out []byte) bool {
|
return func(out []byte) bool {
|
||||||
// First we copy any amount remaining in the buffer.
|
for len(out) > 0 {
|
||||||
n := copy(out, buf)
|
read := len(out)
|
||||||
out, buf = out[n:], buf[n:]
|
|
||||||
|
|
||||||
// Then, if we're requesting more than the buffer size,
|
|
||||||
// generate directly into the output, chunked by readMax.
|
|
||||||
for len(out) >= len(fullBuffer) {
|
|
||||||
read := len(out) - (len(out) % len(fullBuffer))
|
|
||||||
if read > readMax {
|
if read > readMax {
|
||||||
read = readMax
|
read = readMax
|
||||||
}
|
}
|
||||||
|
|
@ -69,22 +56,6 @@ func batched(f func([]byte) error, readMax int) func([]byte) bool {
|
||||||
}
|
}
|
||||||
out = out[read:]
|
out = out[read:]
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there's a partial block left over, fill the buffer,
|
|
||||||
// and copy in the remainder.
|
|
||||||
if len(out) > 0 {
|
|
||||||
if f(fullBuffer[:]) != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
buf = fullBuffer[:]
|
|
||||||
n = copy(out, buf)
|
|
||||||
out, buf = out[n:], buf[n:]
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(out) > 0 {
|
|
||||||
panic("crypto/rand batching failed to fill buffer")
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -95,10 +66,7 @@ func warnBlocked() {
|
||||||
|
|
||||||
func (r *reader) Read(b []byte) (n int, err error) {
|
func (r *reader) Read(b []byte) (n int, err error) {
|
||||||
boring.Unreachable()
|
boring.Unreachable()
|
||||||
r.mu.Lock()
|
if atomic.CompareAndSwapUint32(&r.used, 0, 1) {
|
||||||
defer r.mu.Unlock()
|
|
||||||
if !r.used {
|
|
||||||
r.used = true
|
|
||||||
// First use of randomness. Start timer to warn about
|
// First use of randomness. Start timer to warn about
|
||||||
// being blocked on entropy not being available.
|
// being blocked on entropy not being available.
|
||||||
t := time.AfterFunc(time.Minute, warnBlocked)
|
t := time.AfterFunc(time.Minute, warnBlocked)
|
||||||
|
|
@ -107,14 +75,20 @@ func (r *reader) Read(b []byte) (n int, err error) {
|
||||||
if altGetRandom != nil && altGetRandom(b) {
|
if altGetRandom != nil && altGetRandom(b) {
|
||||||
return len(b), nil
|
return len(b), nil
|
||||||
}
|
}
|
||||||
if r.f == nil {
|
if atomic.LoadUint32(&r.used) != 2 {
|
||||||
f, err := os.Open(urandomDevice)
|
r.mu.Lock()
|
||||||
if err != nil {
|
if r.used != 2 {
|
||||||
return 0, err
|
f, err := os.Open(urandomDevice)
|
||||||
|
if err != nil {
|
||||||
|
r.mu.Unlock()
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
r.f = hideAgainReader{f}
|
||||||
|
atomic.StoreUint32(&r.used, 2)
|
||||||
}
|
}
|
||||||
r.f = bufio.NewReader(hideAgainReader{f})
|
r.mu.Unlock()
|
||||||
}
|
}
|
||||||
return r.f.Read(b)
|
return io.ReadFull(r.f, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hideAgainReader masks EAGAIN reads from /dev/urandom.
|
// hideAgainReader masks EAGAIN reads from /dev/urandom.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue