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
     6  
     7  import (
     8  	"crypto/internal/entropy"
     9  	"crypto/internal/fips140"
    10  	"crypto/internal/randutil"
    11  	"crypto/internal/sysrand"
    12  	"io"
    13  	"sync"
    14  )
    15  
    16  var mu sync.Mutex
    17  var drbg *Counter
    18  
    19  // Read fills b with cryptographically secure random bytes. In FIPS mode, it
    20  // uses an SP 800-90A Rev. 1 Deterministic Random Bit Generator (DRBG).
    21  // Otherwise, it uses the operating system's random number generator.
    22  func Read(b []byte) {
    23  	if !fips140.Enabled {
    24  		sysrand.Read(b)
    25  		return
    26  	}
    27  
    28  	// At every read, 128 random bits from the operating system are mixed as
    29  	// additional input, to make the output as strong as non-FIPS randomness.
    30  	// This is not credited as entropy for FIPS purposes, as allowed by Section
    31  	// 8.7.2: "Note that a DRBG does not rely on additional input to provide
    32  	// entropy, even though entropy could be provided in the additional input".
    33  	additionalInput := new([SeedSize]byte)
    34  	sysrand.Read(additionalInput[:16])
    35  
    36  	mu.Lock()
    37  	defer mu.Unlock()
    38  
    39  	if drbg == nil {
    40  		entropy.Depleted(func(seed *[48]byte) {
    41  			drbg = NewCounter(seed)
    42  		})
    43  	}
    44  
    45  	for len(b) > 0 {
    46  		size := min(len(b), maxRequestSize)
    47  		if reseedRequired := drbg.Generate(b[:size], additionalInput); reseedRequired {
    48  			// See SP 800-90A Rev. 1, Section 9.3.1, Steps 6-8, as explained in
    49  			// Section 9.3.2: if Generate reports a reseed is required, the
    50  			// additional input is passed to Reseed along with the entropy and
    51  			// then nulled before the next Generate call.
    52  			entropy.Depleted(func(seed *[48]byte) {
    53  				drbg.Reseed(seed, additionalInput)
    54  			})
    55  			additionalInput = nil
    56  			continue
    57  		}
    58  		b = b[size:]
    59  	}
    60  }
    61  
    62  // DefaultReader is a sentinel type, embedded in the default
    63  // [crypto/rand.Reader], used to recognize it when passed to
    64  // APIs that accept a rand io.Reader.
    65  type DefaultReader interface{ defaultReader() }
    66  
    67  // ReadWithReader uses Reader to fill b with cryptographically secure random
    68  // bytes. It is intended for use in APIs that expose a rand io.Reader.
    69  //
    70  // If Reader is not the default Reader from crypto/rand,
    71  // [randutil.MaybeReadByte] and [fips140.RecordNonApproved] are called.
    72  func ReadWithReader(r io.Reader, b []byte) error {
    73  	if _, ok := r.(DefaultReader); ok {
    74  		Read(b)
    75  		return nil
    76  	}
    77  
    78  	fips140.RecordNonApproved()
    79  	randutil.MaybeReadByte(r)
    80  	_, err := io.ReadFull(r, b)
    81  	return err
    82  }
    83  
    84  // ReadWithReaderDeterministic is like ReadWithReader, but it doesn't call
    85  // [randutil.MaybeReadByte] on non-default Readers.
    86  func ReadWithReaderDeterministic(r io.Reader, b []byte) error {
    87  	if _, ok := r.(DefaultReader); ok {
    88  		Read(b)
    89  		return nil
    90  	}
    91  
    92  	fips140.RecordNonApproved()
    93  	_, err := io.ReadFull(r, b)
    94  	return err
    95  }
    96  

View as plain text