Source file src/crypto/internal/fips140/drbg/rand.go

     1  // Copyright 2024 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 drbg provides cryptographically secure random bytes
     6  // usable by FIPS code. In FIPS mode it uses an SP 800-90A Rev. 1
     7  // Deterministic Random Bit Generator (DRBG). Otherwise,
     8  // it uses the operating system's random number generator.
     9  package drbg
    10  
    11  import (
    12  	"crypto/internal/fips140"
    13  	"crypto/internal/sysrand"
    14  	"io"
    15  	"sync"
    16  	"sync/atomic"
    17  )
    18  
    19  // getEntropy is very slow (~500µs), so we don't want it on the hot path.
    20  // We keep both a persistent DRBG instance and a pool of additional instances.
    21  // Occasional uses will use drbgInstance, even if the pool was emptied since the
    22  // last use. Frequent concurrent uses will fill the pool and use it.
    23  var drbgInstance atomic.Pointer[Counter]
    24  var drbgPool = sync.Pool{
    25  	New: func() any {
    26  		return NewCounter(getEntropy())
    27  	},
    28  }
    29  
    30  // Read fills b with cryptographically secure random bytes. In FIPS mode, it
    31  // uses an SP 800-90A Rev. 1 Deterministic Random Bit Generator (DRBG).
    32  // Otherwise, it uses the operating system's random number generator.
    33  func Read(b []byte) {
    34  	if testingReader != nil {
    35  		fips140.RecordNonApproved()
    36  		// Avoid letting b escape in the non-testing case.
    37  		bb := make([]byte, len(b))
    38  		testingReader.Read(bb)
    39  		copy(b, bb)
    40  		return
    41  	}
    42  
    43  	if !fips140.Enabled {
    44  		sysrand.Read(b)
    45  		return
    46  	}
    47  
    48  	// At every read, 128 random bits from the operating system are mixed as
    49  	// additional input, to make the output as strong as non-FIPS randomness.
    50  	// This is not credited as entropy for FIPS purposes, as allowed by Section
    51  	// 8.7.2: "Note that a DRBG does not rely on additional input to provide
    52  	// entropy, even though entropy could be provided in the additional input".
    53  	additionalInput := new([SeedSize]byte)
    54  	sysrand.Read(additionalInput[:16])
    55  
    56  	drbg := drbgInstance.Swap(nil)
    57  	if drbg == nil {
    58  		drbg = drbgPool.Get().(*Counter)
    59  	}
    60  	defer func() {
    61  		if !drbgInstance.CompareAndSwap(nil, drbg) {
    62  			drbgPool.Put(drbg)
    63  		}
    64  	}()
    65  
    66  	for len(b) > 0 {
    67  		size := min(len(b), maxRequestSize)
    68  		if reseedRequired := drbg.Generate(b[:size], additionalInput); reseedRequired {
    69  			// See SP 800-90A Rev. 1, Section 9.3.1, Steps 6-8, as explained in
    70  			// Section 9.3.2: if Generate reports a reseed is required, the
    71  			// additional input is passed to Reseed along with the entropy and
    72  			// then nulled before the next Generate call.
    73  			drbg.Reseed(getEntropy(), additionalInput)
    74  			additionalInput = nil
    75  			continue
    76  		}
    77  		b = b[size:]
    78  	}
    79  }
    80  
    81  var testingReader io.Reader
    82  
    83  // SetTestingReader sets a global, deterministic cryptographic randomness source
    84  // for testing purposes. Its Read method must never return an error, it must
    85  // never return short, and it must be safe for concurrent use.
    86  //
    87  // This is only intended to be used by the testing/cryptotest package.
    88  func SetTestingReader(r io.Reader) {
    89  	testingReader = r
    90  }
    91  
    92  // DefaultReader is a sentinel type, embedded in the default
    93  // [crypto/rand.Reader], used to recognize it when passed to
    94  // APIs that accept a rand io.Reader.
    95  //
    96  // Any [io.Reader] that embeds this type is assumed to
    97  // call [Read] as its [io.Reader.Read] method.
    98  type DefaultReader struct{}
    99  
   100  func (d DefaultReader) defaultReader() {}
   101  
   102  // IsDefaultReader reports whether the r embeds the [DefaultReader] type.
   103  func IsDefaultReader(r io.Reader) bool {
   104  	_, ok := r.(interface{ defaultReader() })
   105  	return ok
   106  }
   107  
   108  // ReadWithReader uses Reader to fill b with cryptographically secure random
   109  // bytes. It is intended for use in APIs that expose a rand io.Reader.
   110  func ReadWithReader(r io.Reader, b []byte) error {
   111  	if IsDefaultReader(r) {
   112  		Read(b)
   113  		return nil
   114  	}
   115  
   116  	fips140.RecordNonApproved()
   117  	_, err := io.ReadFull(r, b)
   118  	return err
   119  }
   120  

View as plain text