// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package drbg provides cryptographically secure random bytes // usable by FIPS code. In FIPS mode it uses an SP 800-90A Rev. 1 // Deterministic Random Bit Generator (DRBG). Otherwise, // it uses the operating system's random number generator.
package drbg import ( ) // getEntropy is very slow (~500µs), so we don't want it on the hot path. // We keep both a persistent DRBG instance and a pool of additional instances. // Occasional uses will use drbgInstance, even if the pool was emptied since the // last use. Frequent concurrent uses will fill the pool and use it. var drbgInstance atomic.Pointer[Counter] var drbgPool = sync.Pool{ New: func() any { return NewCounter(getEntropy()) }, } // Read fills b with cryptographically secure random bytes. In FIPS mode, it // uses an SP 800-90A Rev. 1 Deterministic Random Bit Generator (DRBG). // Otherwise, it uses the operating system's random number generator. func ( []byte) { if testingReader != nil { fips140.RecordNonApproved() // Avoid letting b escape in the non-testing case. := make([]byte, len()) testingReader.Read() copy(, ) return } if !fips140.Enabled { sysrand.Read() return } // At every read, 128 random bits from the operating system are mixed as // additional input, to make the output as strong as non-FIPS randomness. // This is not credited as entropy for FIPS purposes, as allowed by Section // 8.7.2: "Note that a DRBG does not rely on additional input to provide // entropy, even though entropy could be provided in the additional input". := new([SeedSize]byte) sysrand.Read([:16]) := drbgInstance.Swap(nil) if == nil { = drbgPool.Get().(*Counter) } defer func() { if !drbgInstance.CompareAndSwap(nil, ) { drbgPool.Put() } }() for len() > 0 { := min(len(), maxRequestSize) if := .Generate([:], ); { // See SP 800-90A Rev. 1, Section 9.3.1, Steps 6-8, as explained in // Section 9.3.2: if Generate reports a reseed is required, the // additional input is passed to Reseed along with the entropy and // then nulled before the next Generate call. .Reseed(getEntropy(), ) = nil continue } = [:] } } var testingReader io.Reader // SetTestingReader sets a global, deterministic cryptographic randomness source // for testing purposes. Its Read method must never return an error, it must // never return short, and it must be safe for concurrent use. // // This is only intended to be used by the testing/cryptotest package. func ( io.Reader) { testingReader = } // DefaultReader is a sentinel type, embedded in the default // [crypto/rand.Reader], used to recognize it when passed to // APIs that accept a rand io.Reader. // // Any Reader that implements this interface is assumed to // call [Read] as its Read method. type DefaultReader interface{ defaultReader() } // ReadWithReader uses Reader to fill b with cryptographically secure random // bytes. It is intended for use in APIs that expose a rand io.Reader. func ( io.Reader, []byte) error { if , := .(DefaultReader); { Read() return nil } fips140.RecordNonApproved() , := io.ReadFull(, ) return }