]> Cypherpunks.ru repositories - gostls13.git/blob - src/crypto/rand/rand_unix.go
[dev.boringcrypto] all: merge master into dev.boringcrypto
[gostls13.git] / src / crypto / rand / rand_unix.go
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 //go:build unix
6
7 // Unix cryptographically secure pseudorandom number
8 // generator.
9
10 package rand
11
12 import (
13         "bufio"
14         "errors"
15         "io"
16         "os"
17         "sync"
18         "sync/atomic"
19         "syscall"
20         "time"
21 )
22
23 import "crypto/internal/boring"
24
25 const urandomDevice = "/dev/urandom"
26
27 func init() {
28         if boring.Enabled {
29                 Reader = boring.RandReader
30                 return
31         }
32         Reader = &reader{}
33 }
34
35 // A reader satisfies reads by reading from urandomDevice
36 type reader struct {
37         f    io.Reader
38         mu   sync.Mutex
39         used int32 // atomic; whether this reader has been used
40 }
41
42 // altGetRandom if non-nil specifies an OS-specific function to get
43 // urandom-style randomness.
44 var altGetRandom func([]byte) (ok bool)
45
46 func warnBlocked() {
47         println("crypto/rand: blocked for 60 seconds waiting to read random data from the kernel")
48 }
49
50 func (r *reader) Read(b []byte) (n int, err error) {
51         boring.Unreachable()
52         if atomic.CompareAndSwapInt32(&r.used, 0, 1) {
53                 // First use of randomness. Start timer to warn about
54                 // being blocked on entropy not being available.
55                 t := time.AfterFunc(time.Minute, warnBlocked)
56                 defer t.Stop()
57         }
58         if altGetRandom != nil && altGetRandom(b) {
59                 return len(b), nil
60         }
61         r.mu.Lock()
62         defer r.mu.Unlock()
63         if r.f == nil {
64                 f, err := os.Open(urandomDevice)
65                 if err != nil {
66                         return 0, err
67                 }
68                 r.f = bufio.NewReader(hideAgainReader{f})
69         }
70         return r.f.Read(b)
71 }
72
73 // hideAgainReader masks EAGAIN reads from /dev/urandom.
74 // See golang.org/issue/9205
75 type hideAgainReader struct {
76         r io.Reader
77 }
78
79 func (hr hideAgainReader) Read(p []byte) (n int, err error) {
80         n, err = hr.r.Read(p)
81         if errors.Is(err, syscall.EAGAIN) {
82                 err = nil
83         }
84         return
85 }