mirror of
https://github.com/XTLS/REALITY.git
synced 2025-08-25 16:05:32 +00:00
Consolidates handling of FIPS 140-3 considerations for the tls package. Considerations specific to certificates are now handled in tls instead of x509 to limit the area-of-effect of FIPS as much as possible. Boringcrypto specific prefixes are renamed as appropriate. For #69536 Co-authored-by: Filippo Valsorda <filippo@golang.org> Change-Id: I1b1fef83c3599e4c9b98ad81db582ac93253030b Reviewed-on: https://go-review.googlesource.com/c/go/+/629675 Reviewed-by: Filippo Valsorda <filippo@golang.org> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Reviewed-by: Russ Cox <rsc@golang.org> Auto-Submit: Filippo Valsorda <filippo@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
103 lines
3.1 KiB
Go
103 lines
3.1 KiB
Go
// 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 (
|
|
"github.com/xtls/reality/entropy"
|
|
// "crypto/internal/fips140"
|
|
"github.com/xtls/reality/randutil"
|
|
// "github.com/xtls/reality/sysrand"
|
|
|
|
"crypto/fips140"
|
|
"crypto/rand"
|
|
"io"
|
|
"sync"
|
|
)
|
|
|
|
var drbgs = sync.Pool{
|
|
New: func() any {
|
|
var c *Counter
|
|
entropy.Depleted(func(seed *[48]byte) {
|
|
c = NewCounter(seed)
|
|
})
|
|
return c
|
|
},
|
|
}
|
|
|
|
// 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 !fips140.Enabled() {
|
|
rand.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)
|
|
rand.Read(additionalInput[:16])
|
|
|
|
drbg := drbgs.Get().(*Counter)
|
|
defer drbgs.Put(drbg)
|
|
|
|
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:]
|
|
}
|
|
}
|
|
|
|
// 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.
|
|
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.
|
|
//
|
|
// If Reader is not the default Reader from crypto/rand,
|
|
// [randutil.MaybeReadByte] and [fips140.RecordNonApproved] are called.
|
|
func ReadWithReader(r io.Reader, b []byte) error {
|
|
if _, ok := r.(DefaultReader); ok {
|
|
Read(b)
|
|
return nil
|
|
}
|
|
|
|
//fips140.RecordNonApproved()
|
|
randutil.MaybeReadByte(r)
|
|
_, err := io.ReadFull(r, b)
|
|
return err
|
|
}
|
|
|
|
// ReadWithReaderDeterministic is like ReadWithReader, but it doesn't call
|
|
// [randutil.MaybeReadByte] on non-default Readers.
|
|
func ReadWithReaderDeterministic(r io.Reader, b []byte) error {
|
|
if _, ok := r.(DefaultReader); ok {
|
|
Read(b)
|
|
return nil
|
|
}
|
|
|
|
//fips140.RecordNonApproved()
|
|
_, err := io.ReadFull(r, b)
|
|
return err
|
|
} |