// 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. // Plan9 cryptographically secure pseudorandom number // generator. package rand import ( "crypto/aes" "encoding/binary" "io" "os" "sync" "time" ) const randomDevice = "/dev/random" func init() { Reader = &reader{} } // reader is a new pseudorandom generator that seeds itself by // reading from /dev/random. The Read method on the returned // reader always returns the full amount asked for, or else it // returns an error. The generator is a fast key erasure RNG. type reader struct { mu sync.Mutex seeded sync.Once seedErr error key [32]byte } func (r *reader) Read(b []byte) (n int, err error) { r.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 { r.seedErr = err return } _, r.seedErr = io.ReadFull(entropy, r.key[:]) }) if r.seedErr != nil { return 0, r.seedErr } r.mu.Lock() blockCipher, err := aes.NewCipher(r.key[:]) if err != nil { r.mu.Unlock() return 0, err } var ( counter uint64 block [aes.BlockSize]byte ) inc := func() { counter++ if counter == 0 { panic("crypto/rand counter wrapped") } binary.LittleEndian.PutUint64(block[:], counter) } blockCipher.Encrypt(r.key[:aes.BlockSize], block[:]) inc() blockCipher.Encrypt(r.key[aes.BlockSize:], block[:]) inc() r.mu.Unlock() n = len(b) for len(b) >= aes.BlockSize { blockCipher.Encrypt(b[:aes.BlockSize], block[:]) inc() b = b[aes.BlockSize:] } if len(b) > 0 { blockCipher.Encrypt(block[:], block[:]) copy(b, block[:]) } return n, nil }