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
35
36
37 func Read(b []byte) {
38 if firstUse.CompareAndSwap(false, true) {
39
40
41 t := time.AfterFunc(time.Minute, warnBlocked)
42 defer t.Stop()
43 }
44 if err := read(b); err != nil || testingOnlyFailRead {
45 var errStr string
46 if !testingOnlyFailRead {
47 errStr = err.Error()
48 } else {
49 errStr = "testing simulated failure"
50 }
51 fatal("crypto/rand: failed to read random data (see https://go.dev/issue/66821): " + errStr)
52 panic("unreachable")
53 }
54 }
55
56
57
58 var urandomOnce sync.Once
59 var urandomFile *os.File
60 var urandomErr error
61
62 func urandomRead(b []byte) error {
63 urandomOnce.Do(func() {
64 urandomFile, urandomErr = os.Open("/dev/urandom")
65 })
66 if urandomErr != nil {
67 return urandomErr
68 }
69 for len(b) > 0 {
70 n, err := urandomFile.Read(b)
71
72
73
74 if err != nil {
75 return err
76 }
77 b = b[n:]
78 }
79 return nil
80 }
81
View as plain text