123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 |
- package seed
- import (
- crand "crypto/rand"
- "fmt"
- "math"
- "math/big"
- "math/rand"
- "sync"
- "sync/atomic"
- "time"
- )
- var (
- m sync.Mutex
- secure int32
- seeded int32
- )
- func cryptoSeed() error {
- defer atomic.StoreInt32(&seeded, 1)
- var err error
- var n *big.Int
- n, err = crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
- if err != nil {
- rand.Seed(time.Now().UTC().UnixNano())
- return err
- }
- rand.Seed(n.Int64())
- atomic.StoreInt32(&secure, 1)
- return nil
- }
- // Init provides best-effort seeding (which is better than running with Go's
- // default seed of 1). If `/dev/urandom` is available, Init() will seed Go's
- // runtime with entropy from `/dev/urandom` and return true because the runtime
- // was securely seeded. If Init() has already initialized the random number or
- // it had failed to securely initialize the random number generation, Init()
- // will return false. See MustInit().
- func Init() (seededSecurely bool, err error) {
- if atomic.LoadInt32(&seeded) == 1 {
- return false, nil
- }
- // Slow-path
- m.Lock()
- defer m.Unlock()
- if err := cryptoSeed(); err != nil {
- return false, err
- }
- return true, nil
- }
- // MustInit provides guaranteed secure seeding. If `/dev/urandom` is not
- // available, MustInit will panic() with an error indicating why reading from
- // `/dev/urandom` failed. MustInit() will upgrade the seed if for some reason a
- // call to Init() failed in the past.
- func MustInit() {
- if atomic.LoadInt32(&secure) == 1 {
- return
- }
- // Slow-path
- m.Lock()
- defer m.Unlock()
- if err := cryptoSeed(); err != nil {
- panic(fmt.Sprintf("Unable to seed the random number generator: %v", err))
- }
- }
- // Secure returns true if a cryptographically secure seed was used to
- // initialize rand.
- func Secure() bool {
- return atomic.LoadInt32(&secure) == 1
- }
- // Seeded returns true if Init has seeded the random number generator.
- func Seeded() bool {
- return atomic.LoadInt32(&seeded) == 1
- }
|