--- /dev/null
+// 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 entropy provides the passive entropy source for the FIPS 140-3
+// module. It is only used in FIPS mode by [crypto/internal/fips/drbg.Read].
+//
+// This complies with IG 9.3.A, Additional Comment 12, which until January 1,
+// 2026 allows new modules to meet an [earlier version] of Resolution 2(b):
+// "A software module that contains an approved DRBG that receives a LOAD
+// command (or its logical equivalent) with entropy obtained from [...] inside
+// the physical perimeter of the operational environment of the module [...]."
+//
+// Distributions that have their own SP 800-90B entropy source should replace
+// this package with their own implementation.
+//
+// [earlier version]: https://csrc.nist.gov/CSRC/media/Projects/cryptographic-module-validation-program/documents/IG%209.3.A%20Resolution%202b%5BMarch%2026%202024%5D.pdf
+package entropy
+
+import "crypto/internal/sysrand"
+
+// Depleted notifies the entropy source that the entropy in the module is
+// "depleted" and provides the callback for the LOAD command.
+func Depleted(LOAD func(*[48]byte)) {
+ var entropy [48]byte
+ sysrand.Read(entropy[:])
+ LOAD(&entropy)
+}
--- /dev/null
+// 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
+
+import (
+ "crypto/internal/entropy"
+ "crypto/internal/fips"
+ "crypto/internal/sysrand"
+ "sync"
+)
+
+var mu sync.Mutex
+var drbg *Counter
+
+// 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 Read(b []byte) {
+ if !fips.Enabled {
+ sysrand.Read(b)
+ 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".
+ additionalInput := new([SeedSize]byte)
+ sysrand.Read(additionalInput[:16])
+
+ mu.Lock()
+ defer mu.Unlock()
+
+ if drbg == nil {
+ entropy.Depleted(func(seed *[48]byte) {
+ drbg = NewCounter(seed)
+ })
+ }
+
+ for len(b) > 0 {
+ size := min(len(b), maxRequestSize)
+ if reseedRequired := drbg.Generate(b[:size], additionalInput); reseedRequired {
+ // 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.
+ entropy.Depleted(func(seed *[48]byte) {
+ drbg.Reseed(seed, additionalInput)
+ })
+ additionalInput = nil
+ continue
+ }
+ b = b[size:]
+ }
+}
--- /dev/null
+// 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 fips
+
+import "internal/godebug"
+
+var Enabled = godebug.New("#fips140").Value() == "on"
import (
"crypto/internal/boring"
+ "crypto/internal/fips"
+ "crypto/internal/fips/drbg"
"crypto/internal/sysrand"
"io"
_ "unsafe"
// - On Windows, Reader uses the ProcessPrng API.
// - On js/wasm, Reader uses the Web Crypto API.
// - On wasip1/wasm, Reader uses random_get.
+//
+// In FIPS 140-3 mode, the output passes through an SP 800-90A Rev. 1
+// Deterministric Random Bit Generator (DRBG).
var Reader io.Reader
func init() {
func (r *reader) Read(b []byte) (n int, err error) {
boring.Unreachable()
- sysrand.Read(b)
+ if fips.Enabled {
+ drbg.Read(b)
+ } else {
+ sysrand.Read(b)
+ }
return len(b), nil
}
< net/mail;
STR < crypto/internal/impl;
- OS < crypto/internal/sysrand;
+
+ OS < crypto/internal/sysrand
+ < crypto/internal/entropy;
# FIPS is the FIPS 140 module.
# It must not depend on external crypto packages.
# Internal packages imported by FIPS might need to retain
# backwards compatibility with older versions of the module.
- STR, crypto/internal/impl, crypto/internal/sysrand
+ STR, crypto/internal/impl, crypto/internal/entropy
< crypto/internal/fips
< crypto/internal/fips/alias
< crypto/internal/fips/subtle