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