Source file
src/crypto/rand/rand_plan9.go
1
2
3
4
5 package rand
6
7 import (
8 "crypto/aes"
9 "internal/byteorder"
10 "io"
11 "os"
12 "sync"
13 "time"
14 )
15
16 const randomDevice = "/dev/random"
17
18
19
20
21
22 var (
23 mu sync.Mutex
24 seeded sync.Once
25 seedErr error
26 key [32]byte
27 )
28
29 func read(b []byte) error {
30 seeded.Do(func() {
31 t := time.AfterFunc(time.Minute, func() {
32 println("crypto/rand: blocked for 60 seconds waiting to read random data from the kernel")
33 })
34 defer t.Stop()
35 entropy, err := os.Open(randomDevice)
36 if err != nil {
37 seedErr = err
38 return
39 }
40 defer entropy.Close()
41 _, seedErr = io.ReadFull(entropy, key[:])
42 })
43 if seedErr != nil {
44 return seedErr
45 }
46
47 mu.Lock()
48 blockCipher, err := aes.NewCipher(key[:])
49 if err != nil {
50 mu.Unlock()
51 return err
52 }
53 var (
54 counter uint64
55 block [aes.BlockSize]byte
56 )
57 inc := func() {
58 counter++
59 if counter == 0 {
60 panic("crypto/rand counter wrapped")
61 }
62 byteorder.LePutUint64(block[:], counter)
63 }
64 blockCipher.Encrypt(key[:aes.BlockSize], block[:])
65 inc()
66 blockCipher.Encrypt(key[aes.BlockSize:], block[:])
67 inc()
68 mu.Unlock()
69
70 for len(b) >= aes.BlockSize {
71 blockCipher.Encrypt(b[:aes.BlockSize], block[:])
72 inc()
73 b = b[aes.BlockSize:]
74 }
75 if len(b) > 0 {
76 blockCipher.Encrypt(block[:], block[:])
77 copy(b, block[:])
78 }
79 return nil
80 }
81
View as plain text