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  	entropy "crypto/internal/entropy/v1.0.0"
    13  	"crypto/internal/fips140"
    14  	"crypto/internal/sysrand"
    15  	"io"
    16  	"sync"
    17  	"sync/atomic"
    18  )
    19  
    20  // memory is a scratch buffer that is accessed between samples by the entropy
    21  // source to expose it to memory access timings.
    22  //
    23  // We reuse it and share it between Seed calls to avoid the significant (~500µs)
    24  // cost of zeroing a new allocation every time. The entropy source accesses it
    25  // using atomics (and doesn't care about its contents).
    26  //
    27  // It should end up in the .noptrbss section, and become backed by physical pages
    28  // at first use. This ensures that programs that do not use the FIPS 140-3 module
    29  // do not incur any memory use or initialization penalties.
    30  var memory entropy.ScratchBuffer
    31  
    32  func getEntropy() *[SeedSize]byte {
    33  	var retries int
    34  	seed, err := entropy.Seed(&memory)
    35  	for err != nil {
    36  		// The CPU jitter-based SP 800-90B entropy source has a non-negligible
    37  		// chance of failing the startup health tests.
    38  		//
    39  		// Each time it does, it enters a permanent failure state, and we
    40  		// restart it anew. This is not expected to happen more than a few times
    41  		// in a row.
    42  		if retries++; retries > 100 {
    43  			panic("fips140/drbg: failed to obtain initial entropy")
    44  		}
    45  		seed, err = entropy.Seed(&memory)
    46  	}
    47  	return &seed
    48  }
    49  
    50  // getEntropy is very slow (~500µs), so we don't want it on the hot path.
    51  // We keep both a persistent DRBG instance and a pool of additional instances.
    52  // Occasional uses will use drbgInstance, even if the pool was emptied since the
    53  // last use. Frequent concurrent uses will fill the pool and use it.
    54  var drbgInstance atomic.Pointer[Counter]
    55  var drbgPool = sync.Pool{
    56  	New: func() any {
    57  		return NewCounter(getEntropy())
    58  	},
    59  }
    60  
    61  // Read fills b with cryptographically secure random bytes. In FIPS mode, it
    62  // uses an SP 800-90A Rev. 1 Deterministic Random Bit Generator (DRBG).
    63  // Otherwise, it uses the operating system's random number generator.
    64  func Read(b []byte) {
    65  	if testingReader != nil {
    66  		fips140.RecordNonApproved()
    67  		// Avoid letting b escape in the non-testing case.
    68  		bb := make([]byte, len(b))
    69  		testingReader.Read(bb)
    70  		copy(b, bb)
    71  		return
    72  	}
    73  
    74  	if !fips140.Enabled {
    75  		sysrand.Read(b)
    76  		return
    77  	}
    78  
    79  	// At every read, 128 random bits from the operating system are mixed as
    80  	// additional input, to make the output as strong as non-FIPS randomness.
    81  	// This is not credited as entropy for FIPS purposes, as allowed by Section
    82  	// 8.7.2: "Note that a DRBG does not rely on additional input to provide
    83  	// entropy, even though entropy could be provided in the additional input".
    84  	additionalInput := new([SeedSize]byte)
    85  	sysrand.Read(additionalInput[:16])
    86  
    87  	drbg := drbgInstance.Swap(nil)
    88  	if drbg == nil {
    89  		drbg = drbgPool.Get().(*Counter)
    90  	}
    91  	defer func() {
    92  		if !drbgInstance.CompareAndSwap(nil, drbg) {
    93  			drbgPool.Put(drbg)
    94  		}
    95  	}()
    96  
    97  	for len(b) > 0 {
    98  		size := min(len(b), maxRequestSize)
    99  		if reseedRequired := drbg.Generate(b[:size], additionalInput); reseedRequired {
   100  			// See SP 800-90A Rev. 1, Section 9.3.1, Steps 6-8, as explained in
   101  			// Section 9.3.2: if Generate reports a reseed is required, the
   102  			// additional input is passed to Reseed along with the entropy and
   103  			// then nulled before the next Generate call.
   104  			drbg.Reseed(getEntropy(), additionalInput)
   105  			additionalInput = nil
   106  			continue
   107  		}
   108  		b = b[size:]
   109  	}
   110  }
   111  
   112  var testingReader io.Reader
   113  
   114  // SetTestingReader sets a global, deterministic cryptographic randomness source
   115  // for testing purposes. Its Read method must never return an error, it must
   116  // never return short, and it must be safe for concurrent use.
   117  //
   118  // This is only intended to be used by the testing/cryptotest package.
   119  func SetTestingReader(r io.Reader) {
   120  	testingReader = r
   121  }
   122  
   123  // DefaultReader is a sentinel type, embedded in the default
   124  // [crypto/rand.Reader], used to recognize it when passed to
   125  // APIs that accept a rand io.Reader.
   126  //
   127  // Any Reader that implements this interface is assumed to
   128  // call [Read] as its Read method.
   129  type DefaultReader interface{ defaultReader() }
   130  
   131  // ReadWithReader uses Reader to fill b with cryptographically secure random
   132  // bytes. It is intended for use in APIs that expose a rand io.Reader.
   133  func ReadWithReader(r io.Reader, b []byte) error {
   134  	if _, ok := r.(DefaultReader); ok {
   135  		Read(b)
   136  		return nil
   137  	}
   138  
   139  	fips140.RecordNonApproved()
   140  	_, err := io.ReadFull(r, b)
   141  	return err
   142  }
   143  

View as plain text