Source file src/crypto/internal/sysrand/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 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(string)
    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  //
    35  // Note that Read is not affected by [testing/cryptotest.SetGlobalRand], and it
    36  // should not be used directly by algorithm implementations.
    37  func Read(b []byte) {
    38  	if firstUse.CompareAndSwap(false, true) {
    39  		// First use of randomness. Start timer to warn about
    40  		// being blocked on entropy not being available.
    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") // To be sure.
    53  	}
    54  }
    55  
    56  // The urandom fallback is only used on Linux kernels before 3.17 and on AIX.
    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  		// Note that we don't ignore EAGAIN because it should not be possible to
    72  		// hit for a blocking read from urandom, although there were
    73  		// unreproducible reports of it at https://go.dev/issue/9205.
    74  		if err != nil {
    75  			return err
    76  		}
    77  		b = b[n:]
    78  	}
    79  	return nil
    80  }
    81  

View as plain text