1// Copyright 2010 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// Plan9 cryptographically secure pseudorandom number 6// generator. 7 8package rand 9 10import ( 11 "crypto/aes" 12 "internal/byteorder" 13 "io" 14 "os" 15 "sync" 16 "time" 17) 18 19const randomDevice = "/dev/random" 20 21func init() { 22 Reader = &reader{} 23} 24 25// reader is a new pseudorandom generator that seeds itself by 26// reading from /dev/random. The Read method on the returned 27// reader always returns the full amount asked for, or else it 28// returns an error. The generator is a fast key erasure RNG. 29type reader struct { 30 mu sync.Mutex 31 seeded sync.Once 32 seedErr error 33 key [32]byte 34} 35 36func (r *reader) Read(b []byte) (n int, err error) { 37 r.seeded.Do(func() { 38 t := time.AfterFunc(time.Minute, func() { 39 println("crypto/rand: blocked for 60 seconds waiting to read random data from the kernel") 40 }) 41 defer t.Stop() 42 entropy, err := os.Open(randomDevice) 43 if err != nil { 44 r.seedErr = err 45 return 46 } 47 defer entropy.Close() 48 _, r.seedErr = io.ReadFull(entropy, r.key[:]) 49 }) 50 if r.seedErr != nil { 51 return 0, r.seedErr 52 } 53 54 r.mu.Lock() 55 blockCipher, err := aes.NewCipher(r.key[:]) 56 if err != nil { 57 r.mu.Unlock() 58 return 0, err 59 } 60 var ( 61 counter uint64 62 block [aes.BlockSize]byte 63 ) 64 inc := func() { 65 counter++ 66 if counter == 0 { 67 panic("crypto/rand counter wrapped") 68 } 69 byteorder.LePutUint64(block[:], counter) 70 } 71 blockCipher.Encrypt(r.key[:aes.BlockSize], block[:]) 72 inc() 73 blockCipher.Encrypt(r.key[aes.BlockSize:], block[:]) 74 inc() 75 r.mu.Unlock() 76 77 n = len(b) 78 for len(b) >= aes.BlockSize { 79 blockCipher.Encrypt(b[:aes.BlockSize], block[:]) 80 inc() 81 b = b[aes.BlockSize:] 82 } 83 if len(b) > 0 { 84 blockCipher.Encrypt(block[:], block[:]) 85 copy(b, block[:]) 86 } 87 return n, nil 88} 89