1 // Copyright 2010 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 5 // Package rand provides cryptographically secure random bytes from the
6 // operating system.
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 // fatal is [runtime.fatal], pushed via linkname.
24 //
25 //go:linkname fatal
26 func fatal([]byte)
27 28 var testingOnlyFailRead bool
29 30 // Read fills b with cryptographically secure random bytes from the operating
31 // system. It always fills b entirely and crashes the program irrecoverably if
32 // an error is encountered. The operating system APIs are documented to never
33 // return an error on all but legacy Linux systems.
34 func Read(b []byte) {
35 if firstUse.CompareAndSwap(false, true) {
36 // First use of randomness. Start timer to warn about
37 // being blocked on entropy not being available.
38 t := time.AfterFunc(time.Minute, warnBlocked)
39 defer t.Stop()
40 }
41 if err := read(b); err != nil || testingOnlyFailRead {
42 var errStr []byte
43 if !testingOnlyFailRead {
44 errStr = []byte(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") // To be sure.
50 }
51 }
52 53 // The urandom fallback is only used on Linux kernels before 3.17 and on AIX.
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 // Note that we don't ignore EAGAIN because it should not be possible to
69 // hit for a blocking read from urandom, although there were
70 // unreproducible reports of it at https://go.dev/issue/9205.
71 if err != nil {
72 return err
73 }
74 b = b[n:]
75 }
76 return nil
77 }
78