mirror of
https://github.com/XTLS/REALITY.git
synced 2026-10-02 03:48:02 +03:00
crypto/internal/mlkem768: move to crypto/internal/fips/mlkem
In the process, replace out-of-module imports with their FIPS versions. For #69536 Change-Id: I83e900b7c38ecf760382e5dca7fd0b1eaa5a5589 Reviewed-on: https://go-review.googlesource.com/c/go/+/626879 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Russ Cox <rsc@golang.org> Auto-Submit: Filippo Valsorda <filippo@golang.org> Reviewed-by: Daniel McCarney <daniel@binaryparadox.net> Reviewed-by: Michael Knyszek <mknyszek@google.com>
This commit is contained in:
+143
@@ -0,0 +1,143 @@
|
||||
// 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/fips140"
|
||||
"github.com/xtls/reality/aes"
|
||||
"github.com/xtls/reality/subtle"
|
||||
"github.com/xtls/reality/byteorder"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
// Counter is an SP 800-90A Rev. 1 CTR_DRBG instantiated with AES-256.
|
||||
//
|
||||
// Per Table 3, it has a security strength of 256 bits, a seed size of 384 bits,
|
||||
// a counter length of 128 bits, a reseed interval of 2^48 requests, and a
|
||||
// maximum request size of 2^19 bits (2^16 bytes, 64 KiB).
|
||||
//
|
||||
// We support a narrow range of parameters that fit the needs of our RNG:
|
||||
// AES-256, no derivation function, no personalization string, no prediction
|
||||
// resistance, and 384-bit additional input.
|
||||
//
|
||||
// WARNING: this type provides tightly scoped support for the DRBG
|
||||
// functionality we need for FIPS 140-3 _only_. This type _should not_ be used
|
||||
// outside of the FIPS 140-3 module for any other use.
|
||||
//
|
||||
// In particular, as documented, Counter does not support the derivation
|
||||
// function, or personalization strings which are necessary for safely using
|
||||
// this DRBG for generic purposes without leaking sensitive values.
|
||||
type Counter struct {
|
||||
// c is instantiated with K as the key and V as the counter.
|
||||
c aes.CTR
|
||||
|
||||
reseedCounter uint64
|
||||
}
|
||||
|
||||
const (
|
||||
keySize = 256 / 8
|
||||
SeedSize = keySize + aes.BlockSize
|
||||
reseedInterval = 1 << 48
|
||||
maxRequestSize = (1 << 19) / 8
|
||||
)
|
||||
|
||||
func NewCounter(entropy *[SeedSize]byte) *Counter {
|
||||
// CTR_DRBG_Instantiate_algorithm, per Section 10.2.1.3.1.
|
||||
//fips140.RecordApproved()
|
||||
|
||||
K := make([]byte, keySize)
|
||||
V := make([]byte, aes.BlockSize)
|
||||
|
||||
// V starts at 0, but is incremented in CTR_DRBG_Update before each use,
|
||||
// unlike AES-CTR where it is incremented after each use.
|
||||
V[len(V)-1] = 1
|
||||
|
||||
cipher, err := aes.New(K)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c := &Counter{}
|
||||
c.c = *aes.NewCTR(cipher, V)
|
||||
c.update(entropy)
|
||||
c.reseedCounter = 1
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Counter) update(seed *[SeedSize]byte) {
|
||||
// CTR_DRBG_Update, per Section 10.2.1.2.
|
||||
|
||||
temp := make([]byte, SeedSize)
|
||||
c.c.XORKeyStream(temp, seed[:])
|
||||
K := temp[:keySize]
|
||||
V := temp[keySize:]
|
||||
|
||||
// Again, we pre-increment V, like in NewCounter.
|
||||
increment((*[aes.BlockSize]byte)(V))
|
||||
|
||||
cipher, err := aes.New(K)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
c.c = *aes.NewCTR(cipher, V)
|
||||
}
|
||||
|
||||
func increment(v *[aes.BlockSize]byte) {
|
||||
hi := byteorder.BEUint64(v[:8])
|
||||
lo := byteorder.BEUint64(v[8:])
|
||||
lo, c := bits.Add64(lo, 1, 0)
|
||||
hi, _ = bits.Add64(hi, 0, c)
|
||||
byteorder.BEPutUint64(v[:8], hi)
|
||||
byteorder.BEPutUint64(v[8:], lo)
|
||||
}
|
||||
|
||||
func (c *Counter) Reseed(entropy, additionalInput *[SeedSize]byte) {
|
||||
// CTR_DRBG_Reseed_algorithm, per Section 10.2.1.4.1.
|
||||
//fips140.RecordApproved()
|
||||
|
||||
var seed [SeedSize]byte
|
||||
subtle.XORBytes(seed[:], entropy[:], additionalInput[:])
|
||||
c.update(&seed)
|
||||
c.reseedCounter = 1
|
||||
}
|
||||
|
||||
// Generate produces at most maxRequestSize bytes of random data in out.
|
||||
func (c *Counter) Generate(out []byte, additionalInput *[SeedSize]byte) (reseedRequired bool) {
|
||||
// CTR_DRBG_Generate_algorithm, per Section 10.2.1.5.1.
|
||||
//fips140.RecordApproved()
|
||||
|
||||
if len(out) > maxRequestSize {
|
||||
panic("crypto/drbg: internal error: request size exceeds maximum")
|
||||
}
|
||||
|
||||
// Step 1.
|
||||
if c.reseedCounter > reseedInterval {
|
||||
return true
|
||||
}
|
||||
|
||||
// Step 2.
|
||||
if additionalInput != nil {
|
||||
c.update(additionalInput)
|
||||
} else {
|
||||
// If the additional input is null, the first CTR_DRBG_Update is
|
||||
// skipped, but the additional input is replaced with an all-zero string
|
||||
// for the second CTR_DRBG_Update.
|
||||
additionalInput = new([SeedSize]byte)
|
||||
}
|
||||
|
||||
// Steps 3-5.
|
||||
clear(out)
|
||||
c.c.XORKeyStream(out, out)
|
||||
aes.RoundToBlock(&c.c)
|
||||
|
||||
// Step 6.
|
||||
c.update(additionalInput)
|
||||
|
||||
// Step 7.
|
||||
c.reseedCounter++
|
||||
|
||||
// Step 8.
|
||||
return false
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
// 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/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
|
||||
}
|
||||
Reference in New Issue
Block a user