1
2
3
4
5
6
7 package sysrand
8
9 import (
10 "os"
11 "sync"
12 "sync/atomic"
13 "time"
14 _ "unsafe"
15 )
16
17 var firstUse atomic.Bool
18
19 func warnBlocked() {
20 println("crypto/rand: blocked for 60 seconds waiting to read random data from the kernel")
21 }
22
23
24
25
26 func fatal(string)
27
28 var testingOnlyFailRead bool
29
30
31
32
33
34 func Read(b []byte) {
35 if firstUse.CompareAndSwap(false, true) {
36
37
38 t := time.AfterFunc(time.Minute, warnBlocked)
39 defer t.Stop()
40 }
41 if err := read(b); err != nil || testingOnlyFailRead {
42 var errStr string
43 if !testingOnlyFailRead {
44 errStr = err.Error()
45 } else {
46 errStr = "testing simulated failure"
47 }
48 fatal("crypto/rand: failed to read random data (see https://go.dev/issue/66821): " + errStr)
49 panic("unreachable")
50 }
51 }
52
53
54
55 var urandomOnce sync.Once
56 var urandomFile *os.File
57 var urandomErr error
58
59 func urandomRead(b []byte) error {
60 urandomOnce.Do(func() {
61 urandomFile, urandomErr = os.Open("/dev/urandom")
62 })
63 if urandomErr != nil {
64 return urandomErr
65 }
66 for len(b) > 0 {
67 n, err := urandomFile.Read(b)
68
69
70
71 if err != nil {
72 return err
73 }
74 b = b[n:]
75 }
76 return nil
77 }
78
View as plain text