summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/sean-/seed/init.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/sean-/seed/init.go')
-rw-r--r--vendor/github.com/sean-/seed/init.go84
1 files changed, 84 insertions, 0 deletions
diff --git a/vendor/github.com/sean-/seed/init.go b/vendor/github.com/sean-/seed/init.go
new file mode 100644
index 000000000..248d6b636
--- /dev/null
+++ b/vendor/github.com/sean-/seed/init.go
@@ -0,0 +1,84 @@
+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
+}