github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/crypto/rand/rand_plan9.go (about) 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 8 package rand 9 10 import ( 11 "crypto/aes" 12 "encoding/binary" 13 "io" 14 "os" 15 "sync" 16 "time" 17 ) 18 19 const randomDevice = "/dev/random" 20 21 func 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. 29 type reader struct { 30 mu sync.Mutex 31 seeded sync.Once 32 seedErr error 33 key [32]byte 34 } 35 36 func (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 _, r.seedErr = io.ReadFull(entropy, r.key[:]) 48 }) 49 if r.seedErr != nil { 50 return 0, r.seedErr 51 } 52 53 r.mu.Lock() 54 blockCipher, err := aes.NewCipher(r.key[:]) 55 if err != nil { 56 r.mu.Unlock() 57 return 0, err 58 } 59 var ( 60 counter uint64 61 block [aes.BlockSize]byte 62 ) 63 inc := func() { 64 counter++ 65 if counter == 0 { 66 panic("crypto/rand counter wrapped") 67 } 68 binary.LittleEndian.PutUint64(block[:], counter) 69 } 70 blockCipher.Encrypt(r.key[:aes.BlockSize], block[:]) 71 inc() 72 blockCipher.Encrypt(r.key[aes.BlockSize:], block[:]) 73 inc() 74 r.mu.Unlock() 75 76 n = len(b) 77 for len(b) >= aes.BlockSize { 78 blockCipher.Encrypt(b[:aes.BlockSize], block[:]) 79 inc() 80 b = b[aes.BlockSize:] 81 } 82 if len(b) > 0 { 83 blockCipher.Encrypt(block[:], block[:]) 84 copy(b, block[:]) 85 } 86 return n, nil 87 }