...
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 "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
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 _, 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 }
88
View as plain text