Source file
src/crypto/rand/rand_plan9.go
1
2
3
4
5
6
7
8 package rand
9
10 import (
11 "crypto/aes"
12 "internal/byteorder"
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
26
27
28
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 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
View as plain text