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 entropy "crypto/internal/entropy/v1.0.0" 13 "crypto/internal/fips140" 14 "crypto/internal/sysrand" 15 "io" 16 "sync" 17 "sync/atomic" 18 ) 19 20 // memory is a scratch buffer that is accessed between samples by the entropy 21 // source to expose it to memory access timings. 22 // 23 // We reuse it and share it between Seed calls to avoid the significant (~500µs) 24 // cost of zeroing a new allocation every time. The entropy source accesses it 25 // using atomics (and doesn't care about its contents). 26 // 27 // It should end up in the .noptrbss section, and become backed by physical pages 28 // at first use. This ensures that programs that do not use the FIPS 140-3 module 29 // do not incur any memory use or initialization penalties. 30 var memory entropy.ScratchBuffer 31 32 func getEntropy() *[SeedSize]byte { 33 var retries int 34 seed, err := entropy.Seed(&memory) 35 for err != nil { 36 // The CPU jitter-based SP 800-90B entropy source has a non-negligible 37 // chance of failing the startup health tests. 38 // 39 // Each time it does, it enters a permanent failure state, and we 40 // restart it anew. This is not expected to happen more than a few times 41 // in a row. 42 if retries++; retries > 100 { 43 panic("fips140/drbg: failed to obtain initial entropy") 44 } 45 seed, err = entropy.Seed(&memory) 46 } 47 return &seed 48 } 49 50 // getEntropy is very slow (~500µs), so we don't want it on the hot path. 51 // We keep both a persistent DRBG instance and a pool of additional instances. 52 // Occasional uses will use drbgInstance, even if the pool was emptied since the 53 // last use. Frequent concurrent uses will fill the pool and use it. 54 var drbgInstance atomic.Pointer[Counter] 55 var drbgPool = sync.Pool{ 56 New: func() any { 57 return NewCounter(getEntropy()) 58 }, 59 } 60 61 // Read fills b with cryptographically secure random bytes. In FIPS mode, it 62 // uses an SP 800-90A Rev. 1 Deterministic Random Bit Generator (DRBG). 63 // Otherwise, it uses the operating system's random number generator. 64 func Read(b []byte) { 65 if testingReader != nil { 66 fips140.RecordNonApproved() 67 // Avoid letting b escape in the non-testing case. 68 bb := make([]byte, len(b)) 69 testingReader.Read(bb) 70 copy(b, bb) 71 return 72 } 73 74 if !fips140.Enabled { 75 sysrand.Read(b) 76 return 77 } 78 79 // At every read, 128 random bits from the operating system are mixed as 80 // additional input, to make the output as strong as non-FIPS randomness. 81 // This is not credited as entropy for FIPS purposes, as allowed by Section 82 // 8.7.2: "Note that a DRBG does not rely on additional input to provide 83 // entropy, even though entropy could be provided in the additional input". 84 additionalInput := new([SeedSize]byte) 85 sysrand.Read(additionalInput[:16]) 86 87 drbg := drbgInstance.Swap(nil) 88 if drbg == nil { 89 drbg = drbgPool.Get().(*Counter) 90 } 91 defer func() { 92 if !drbgInstance.CompareAndSwap(nil, drbg) { 93 drbgPool.Put(drbg) 94 } 95 }() 96 97 for len(b) > 0 { 98 size := min(len(b), maxRequestSize) 99 if reseedRequired := drbg.Generate(b[:size], additionalInput); reseedRequired { 100 // See SP 800-90A Rev. 1, Section 9.3.1, Steps 6-8, as explained in 101 // Section 9.3.2: if Generate reports a reseed is required, the 102 // additional input is passed to Reseed along with the entropy and 103 // then nulled before the next Generate call. 104 drbg.Reseed(getEntropy(), additionalInput) 105 additionalInput = nil 106 continue 107 } 108 b = b[size:] 109 } 110 } 111 112 var testingReader io.Reader 113 114 // SetTestingReader sets a global, deterministic cryptographic randomness source 115 // for testing purposes. Its Read method must never return an error, it must 116 // never return short, and it must be safe for concurrent use. 117 // 118 // This is only intended to be used by the testing/cryptotest package. 119 func SetTestingReader(r io.Reader) { 120 testingReader = r 121 } 122 123 // DefaultReader is a sentinel type, embedded in the default 124 // [crypto/rand.Reader], used to recognize it when passed to 125 // APIs that accept a rand io.Reader. 126 // 127 // Any Reader that implements this interface is assumed to 128 // call [Read] as its Read method. 129 type DefaultReader interface{ defaultReader() } 130 131 // ReadWithReader uses Reader to fill b with cryptographically secure random 132 // bytes. It is intended for use in APIs that expose a rand io.Reader. 133 func ReadWithReader(r io.Reader, b []byte) error { 134 if _, ok := r.(DefaultReader); ok { 135 Read(b) 136 return nil 137 } 138 139 fips140.RecordNonApproved() 140 _, err := io.ReadFull(r, b) 141 return err 142 } 143