Source file src/crypto/rand/rand.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  // Package rand implements a cryptographically secure
     6  // random number generator.
     7  package rand
     8  
     9  import (
    10  	"crypto/internal/boring"
    11  	"io"
    12  	"os"
    13  	"sync"
    14  	"sync/atomic"
    15  	"time"
    16  	_ "unsafe"
    17  )
    18  
    19  // Reader is a global, shared instance of a cryptographically
    20  // secure random number generator. It is safe for concurrent use.
    21  //
    22  //   - On Linux, FreeBSD, Dragonfly, and Solaris, Reader uses getrandom(2).
    23  //   - On legacy Linux (< 3.17), Reader opens /dev/urandom on first use.
    24  //   - On macOS, iOS, and OpenBSD Reader, uses arc4random_buf(3).
    25  //   - On NetBSD, Reader uses the kern.arandom sysctl.
    26  //   - On Windows, Reader uses the ProcessPrng API.
    27  //   - On js/wasm, Reader uses the Web Crypto API.
    28  //   - On wasip1/wasm, Reader uses random_get.
    29  var Reader io.Reader
    30  
    31  func init() {
    32  	if boring.Enabled {
    33  		Reader = boring.RandReader
    34  		return
    35  	}
    36  	Reader = &reader{}
    37  }
    38  
    39  var firstUse atomic.Bool
    40  
    41  func warnBlocked() {
    42  	println("crypto/rand: blocked for 60 seconds waiting to read random data from the kernel")
    43  }
    44  
    45  type reader struct{}
    46  
    47  // Read always returns len(b) or an error.
    48  func (r *reader) Read(b []byte) (n int, err error) {
    49  	boring.Unreachable()
    50  	if firstUse.CompareAndSwap(false, true) {
    51  		// First use of randomness. Start timer to warn about
    52  		// being blocked on entropy not being available.
    53  		t := time.AfterFunc(time.Minute, warnBlocked)
    54  		defer t.Stop()
    55  	}
    56  	if err := read(b); err != nil {
    57  		return 0, err
    58  	}
    59  	return len(b), nil
    60  }
    61  
    62  // fatal is [runtime.fatal], pushed via linkname.
    63  //
    64  //go:linkname fatal
    65  func fatal(string)
    66  
    67  // Read fills b with cryptographically secure random bytes. It never returns an
    68  // error, and always fills b entirely.
    69  //
    70  // Read calls [io.ReadFull] on [Reader] and crashes the program irrecoverably if
    71  // an error is returned. The default Reader uses operating system APIs that are
    72  // documented to never return an error on all but legacy Linux systems.
    73  func Read(b []byte) (n int, err error) {
    74  	// We don't want b to escape to the heap, but escape analysis can't see
    75  	// through a potentially overridden Reader, so we special-case the default
    76  	// case which we can keep non-escaping, and in the general case we read into
    77  	// a heap buffer and copy from it.
    78  	if r, ok := Reader.(*reader); ok {
    79  		_, err = r.Read(b)
    80  	} else {
    81  		bb := make([]byte, len(b))
    82  		_, err = io.ReadFull(Reader, bb)
    83  		copy(b, bb)
    84  	}
    85  	if err != nil {
    86  		fatal("crypto/rand: failed to read random data (see https://go.dev/issue/66821): " + err.Error())
    87  		panic("unreachable") // To be sure.
    88  	}
    89  	return len(b), nil
    90  }
    91  
    92  // The urandom fallback is only used on Linux kernels before 3.17 and on AIX.
    93  
    94  var urandomOnce sync.Once
    95  var urandomFile *os.File
    96  var urandomErr error
    97  
    98  func urandomRead(b []byte) error {
    99  	urandomOnce.Do(func() {
   100  		urandomFile, urandomErr = os.Open("/dev/urandom")
   101  	})
   102  	if urandomErr != nil {
   103  		return urandomErr
   104  	}
   105  	for len(b) > 0 {
   106  		n, err := urandomFile.Read(b)
   107  		// Note that we don't ignore EAGAIN because it should not be possible to
   108  		// hit for a blocking read from urandom, although there were
   109  		// unreproducible reports of it at https://go.dev/issue/9205.
   110  		if err != nil {
   111  			return err
   112  		}
   113  		b = b[n:]
   114  	}
   115  	return nil
   116  }
   117  

View as plain text