| // Copyright 2010 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 sysrand |
| |
| import ( |
| "internal/byteorder" |
| "internal/chacha8rand" |
| "io" |
| "os" |
| "sync" |
| ) |
| |
| 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. |
| |
| var ( |
| mu sync.Mutex |
| seeded sync.Once |
| seedErr error |
| state chacha8rand.State |
| ) |
| |
| func read(b []byte) error { |
| seeded.Do(func() { |
| entropy, err := os.Open(randomDevice) |
| if err != nil { |
| seedErr = err |
| return |
| } |
| defer entropy.Close() |
| 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() |
| defer mu.Unlock() |
| |
| for len(b) >= 8 { |
| if x, ok := state.Next(); ok { |
| byteorder.BEPutUint64(b, x) |
| b = b[8:] |
| } else { |
| state.Refill() |
| } |
| } |
| 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 |
| } |