rand.mx raw

   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 := &[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