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

View as plain text