mirror of https://github.com/golang/go.git
crypto/rand: replace crypto/aes with internal/chacha8rand for plan9
We will need to import this functionality from the FIPS module, and we can't import AES from there. Plan 9 is not going to be FIPS validated anyway, so we can use non-approved cryptography. For #69536 Change-Id: I7921ec0829b576de2e80f3a7d0a9a776ff387684 Reviewed-on: https://go-review.googlesource.com/c/go/+/624975 Reviewed-by: Daniel McCarney <daniel@binaryparadox.net> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Filippo Valsorda <filippo@golang.org> Reviewed-by: Roland Shoemaker <roland@golang.org> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
This commit is contained in:
parent
c4aea46784
commit
f705cf8f96
|
|
@ -5,76 +5,68 @@
|
|||
package rand
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"internal/byteorder"
|
||||
"internal/chacha8rand"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const randomDevice = "/dev/random"
|
||||
|
||||
// This is a pseudorandom generator that seeds itself by reading from
|
||||
// /dev/random. The read function always returns the full amount asked for, or
|
||||
// else it returns an error. The generator is a fast key erasure RNG.
|
||||
// else it returns an error.
|
||||
|
||||
var (
|
||||
mu sync.Mutex
|
||||
seeded sync.Once
|
||||
seedErr error
|
||||
key [32]byte
|
||||
state chacha8rand.State
|
||||
)
|
||||
|
||||
func read(b []byte) error {
|
||||
seeded.Do(func() {
|
||||
t := time.AfterFunc(time.Minute, func() {
|
||||
println("crypto/rand: blocked for 60 seconds waiting to read random data from the kernel")
|
||||
})
|
||||
defer t.Stop()
|
||||
entropy, err := os.Open(randomDevice)
|
||||
if err != nil {
|
||||
seedErr = err
|
||||
return
|
||||
}
|
||||
defer entropy.Close()
|
||||
_, seedErr = io.ReadFull(entropy, key[:])
|
||||
var seed [32]byte
|
||||
_, err = io.ReadFull(entropy, seed[:])
|
||||
if err != nil {
|
||||
seedErr = err
|
||||
return
|
||||
}
|
||||
state.Init(seed)
|
||||
})
|
||||
if seedErr != nil {
|
||||
return seedErr
|
||||
}
|
||||
|
||||
mu.Lock()
|
||||
blockCipher, err := aes.NewCipher(key[:])
|
||||
if err != nil {
|
||||
mu.Unlock()
|
||||
return err
|
||||
}
|
||||
var (
|
||||
counter uint64
|
||||
block [aes.BlockSize]byte
|
||||
)
|
||||
inc := func() {
|
||||
counter++
|
||||
if counter == 0 {
|
||||
panic("crypto/rand counter wrapped")
|
||||
}
|
||||
byteorder.LePutUint64(block[:], counter)
|
||||
}
|
||||
blockCipher.Encrypt(key[:aes.BlockSize], block[:])
|
||||
inc()
|
||||
blockCipher.Encrypt(key[aes.BlockSize:], block[:])
|
||||
inc()
|
||||
mu.Unlock()
|
||||
defer mu.Unlock()
|
||||
|
||||
for len(b) >= aes.BlockSize {
|
||||
blockCipher.Encrypt(b[:aes.BlockSize], block[:])
|
||||
inc()
|
||||
b = b[aes.BlockSize:]
|
||||
for len(b) >= 8 {
|
||||
if x, ok := state.Next(); ok {
|
||||
byteorder.BePutUint64(b, x)
|
||||
b = b[8:]
|
||||
} else {
|
||||
state.Refill()
|
||||
}
|
||||
}
|
||||
if len(b) > 0 {
|
||||
blockCipher.Encrypt(block[:], block[:])
|
||||
copy(b, block[:])
|
||||
for len(b) > 0 {
|
||||
if x, ok := state.Next(); ok {
|
||||
var buf [8]byte
|
||||
byteorder.BePutUint64(buf[:], x)
|
||||
n := copy(b, buf[:])
|
||||
b = b[n:]
|
||||
} else {
|
||||
state.Refill()
|
||||
}
|
||||
}
|
||||
state.Reseed()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue