// 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 ( entropy ) // memory is a scratch buffer that is accessed between samples by the entropy // source to expose it to memory access timings. // // We reuse it and share it between Seed calls to avoid the significant (~500µs) // cost of zeroing a new allocation every time. The entropy source accesses it // using atomics (and doesn't care about its contents). // // It should end up in the .noptrbss section, and become backed by physical pages // at first use. This ensures that programs that do not use the FIPS 140-3 module // do not incur any memory use or initialization penalties. var memory entropy.ScratchBuffer func getEntropy() *[SeedSize]byte { var int , := entropy.Seed(&memory) for != nil { // The CPU jitter-based SP 800-90B entropy source has a non-negligible // chance of failing the startup health tests. // // Each time it does, it enters a permanent failure state, and we // restart it anew. This is not expected to happen more than a few times // in a row. if ++; > 100 { panic("fips140/drbg: failed to obtain initial entropy") } , = entropy.Seed(&memory) } return & } // 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 }