"bytes"
"crypto/internal/boring"
"crypto/internal/fips140/ecdh"
+ "crypto/internal/fips140only"
"errors"
"io"
)
return k, nil
}
+ if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) {
+ return nil, errors.New("crypto/ecdh: only crypto/rand.Reader is allowed in FIPS 140-only mode")
+ }
+
privateKey, err := c.generate(rand)
if err != nil {
return nil, err
"crypto/internal/boring"
"crypto/internal/boring/bbig"
"crypto/internal/fips140/ecdsa"
+ "crypto/internal/fips140only"
"crypto/internal/randutil"
"crypto/sha512"
"crypto/subtle"
}
func generateFIPS[P ecdsa.Point[P]](curve elliptic.Curve, c *ecdsa.Curve[P], rand io.Reader) (*PrivateKey, error) {
+ if fips140only.Enabled && fips140only.ApprovedRandomReader(rand) {
+ return nil, errors.New("crypto/ecdsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
+ }
privateKey, err := ecdsa.GenerateKey(c, rand)
if err != nil {
return nil, err
}
func signFIPS[P ecdsa.Point[P]](c *ecdsa.Curve[P], priv *PrivateKey, rand io.Reader, hash []byte) ([]byte, error) {
+ if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) {
+ return nil, errors.New("crypto/ecdsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
+ }
// privateKeyToFIPS is very slow in FIPS mode because it performs a
// Sign+Verify cycle per FIPS 140-3 IG 10.3.A. We should find a way to cache
// it or attach it to the PrivateKey.
import (
"crypto/internal/entropy"
"crypto/internal/fips140"
+ "crypto/internal/randutil"
"crypto/internal/sysrand"
+ "io"
"sync"
)
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
+}
"crypto/internal/fips140/drbg"
"crypto/internal/fips140/nistec"
"crypto/internal/fips140deps/byteorder"
- "crypto/internal/randutil"
"errors"
"io"
"math/bits"
}
// GenerateKey generates a new ECDSA private key pair for the specified curve.
-//
-// In FIPS mode, rand is ignored.
func GenerateKey[P Point[P]](c *Curve[P], rand io.Reader) (*PrivateKey, error) {
fips140.RecordApproved()
// This procedure is equivalent to Key Pair Generation by Testing
for {
key := make([]byte, len(c.N))
- if fips140.Enabled {
- drbg.Read(key)
- } else {
- randutil.MaybeReadByte(rand)
- if _, err := io.ReadFull(rand, key); err != nil {
- return nil, err
- }
- // In tests, rand will return all zeros and NewPrivateKey will reject
- // the zero key as it generates the identity as a public key. This also
- // makes this function consistent with crypto/elliptic.GenerateKey.
- key[1] ^= 0x42
+ if err := drbg.ReadWithReader(rand, key); err != nil {
+ return nil, err
}
+ // In tests, rand will return all zeros and NewPrivateKey will reject
+ // the zero key as it generates the identity as a public key. This also
+ // makes this function consistent with crypto/elliptic.GenerateKey.
+ key[1] ^= 0x42
// Mask off any excess bits if the size of the underlying field is not a
// whole number of bytes, which is only the case for P-521.
func fipsPCT[P Point[P]](c *Curve[P], k *PrivateKey) error {
return fips140.PCT("ECDSA PCT", func() error {
hash := testHash()
- sig, err := Sign(c, sha512.New, k, nil, hash)
+ drbg := newDRBG(sha512.New, k.d, bits2octets(P256(), hash), nil)
+ sig, err := sign(c, k, drbg, hash)
if err != nil {
return err
}
"crypto/internal/fips140/bigmod"
"crypto/internal/fips140/drbg"
"crypto/internal/fips140/nistec"
- "crypto/internal/randutil"
"errors"
"io"
"sync"
}
// GenerateKey generates a new ECDSA private key pair for the specified curve.
-//
-// In FIPS mode, rand is ignored.
func GenerateKey[P Point[P]](c *Curve[P], rand io.Reader) (*PrivateKey, error) {
fips140.RecordApproved()
k, Q, err := randomPoint(c, func(b []byte) error {
- if fips140.Enabled {
- drbg.Read(b)
- return nil
- } else {
- randutil.MaybeReadByte(rand)
- _, err := io.ReadFull(rand, b)
- return err
- }
+ return drbg.ReadWithReader(rand, b)
})
if err != nil {
return nil, err
// the hash function H) using the private key, priv. If the hash is longer than
// the bit-length of the private key's curve order, the hash will be truncated
// to that length.
-//
-// The signature is randomized. If FIPS mode is enabled, rand is ignored.
func Sign[P Point[P], H fips140.Hash](c *Curve[P], h func() H, priv *PrivateKey, rand io.Reader, hash []byte) (*Signature, error) {
if priv.pub.curve != c.curve {
return nil, errors.New("ecdsa: private key does not match curve")
// advantage of closely resembling Deterministic ECDSA.
Z := make([]byte, len(priv.d))
- if fips140.Enabled {
- drbg.Read(Z)
- } else {
- randutil.MaybeReadByte(rand)
- if _, err := io.ReadFull(rand, Z); err != nil {
- return nil, err
- }
+ if err := drbg.ReadWithReader(rand, Z); err != nil {
+ return nil, err
}
// See https://github.com/cfrg/draft-irtf-cfrg-det-sigs-with-noise/issues/6
"crypto/internal/fips140/edwards25519"
"crypto/internal/fips140/sha512"
"errors"
- "io"
"strconv"
)
}
// GenerateKey generates a new Ed25519 private key pair.
-//
-// In FIPS mode, rand is ignored. Otherwise, the output of this function is
-// deterministic, and equivalent to reading 32 bytes from rand, and passing them
-// to [NewKeyFromSeed].
-func GenerateKey(rand io.Reader) (*PrivateKey, error) {
+func GenerateKey() (*PrivateKey, error) {
priv := &PrivateKey{}
- return generateKey(priv, rand)
+ return generateKey(priv)
}
-func generateKey(priv *PrivateKey, rand io.Reader) (*PrivateKey, error) {
+func generateKey(priv *PrivateKey) (*PrivateKey, error) {
fips140.RecordApproved()
- if fips140.Enabled {
- drbg.Read(priv.seed[:])
- } else {
- if _, err := io.ReadFull(rand, priv.seed[:]); err != nil {
- return nil, err
- }
- }
+ drbg.Read(priv.seed[:])
precomputePrivateKey(priv)
if err := fipsPCT(priv); err != nil {
// This clearly can't happen, but FIPS 140-3 requires that we check.
"crypto/internal/fips140"
"crypto/internal/fips140/bigmod"
"crypto/internal/fips140/drbg"
- "crypto/internal/randutil"
"errors"
"io"
)
// GenerateKey generates a new RSA key pair of the given bit size.
// bits must be at least 128.
-//
-// When operating in FIPS mode, rand is ignored.
func GenerateKey(rand io.Reader, bits int) (*PrivateKey, error) {
if bits < 128 {
return nil, errors.New("rsa: key too small")
}
// randomPrime returns a random prime number of the given bit size following
-// the process in FIPS 186-5, Appendix A.1.3. rand is ignored in FIPS mode.
+// the process in FIPS 186-5, Appendix A.1.3.
func randomPrime(rand io.Reader, bits int) ([]byte, error) {
if bits < 64 {
return nil, errors.New("rsa: prime size must be at least 32-bit")
b := make([]byte, (bits+7)/8)
for {
- if fips140.Enabled {
- drbg.Read(b)
- } else {
- randutil.MaybeReadByte(rand)
- if _, err := io.ReadFull(rand, b); err != nil {
- return nil, err
- }
+ if err := drbg.ReadWithReader(rand, b); err != nil {
+ return nil, err
}
if excess := len(b)*8 - bits; excess != 0 {
b[0] >>= excess
}
// SignPSS calculates the signature of hashed using RSASSA-PSS.
-//
-// In FIPS mode, rand is ignored and can be nil.
func SignPSS(rand io.Reader, priv *PrivateKey, hash fips140.Hash, hashed []byte, saltLength int) ([]byte, error) {
fipsSelfTest()
fips140.RecordApproved()
fips140.RecordNonApproved()
}
salt := make([]byte, saltLength)
- if fips140.Enabled {
- drbg.Read(salt)
- } else {
- if _, err := io.ReadFull(rand, salt); err != nil {
- return nil, err
- }
+ if err := drbg.ReadWithReaderDeterministic(rand, salt); err != nil {
+ return nil, err
}
emBits := priv.pub.N.BitLen() - 1
}
// EncryptOAEP encrypts the given message with RSAES-OAEP.
-//
-// In FIPS mode, random is ignored and can be nil.
func EncryptOAEP(hash, mgfHash fips140.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) ([]byte, error) {
// Note that while we don't commit to deterministic execution with respect
// to the random stream, we also don't apply MaybeReadByte, so per Hyrum's
db[len(db)-len(msg)-1] = 1
copy(db[len(db)-len(msg):], msg)
- if fips140.Enabled {
- drbg.Read(seed)
- } else {
- _, err := io.ReadFull(random, seed)
- if err != nil {
- return nil, err
- }
+ if err := drbg.ReadWithReaderDeterministic(random, seed); err != nil {
+ return nil, err
}
mgf1XOR(db, mgfHash, seed)
package fips140only
import (
+ "crypto/internal/fips140/drbg"
"crypto/internal/fips140/sha256"
"crypto/internal/fips140/sha3"
"crypto/internal/fips140/sha512"
"hash"
"internal/godebug"
+ "io"
)
// Enabled reports whether FIPS 140-only mode is enabled, in which non-approved
return false
}
}
+
+func ApprovedRandomReader(r io.Reader) bool {
+ _, ok := r.(drbg.DefaultReader)
+ return ok
+}
t.Fatal(err)
}
ecdsa.SignDeterministic(ecdsa.P256(), sha256.New, kDSA, make([]byte, 32))
- k25519, err := ed25519.GenerateKey(rand.Reader)
+ k25519, err := ed25519.GenerateKey()
if err != nil {
t.Fatal(err)
}
Reader = &reader{}
}
-type reader struct{}
+type reader struct {
+ drbg.DefaultReader
+}
func (r *reader) Read(b []byte) (n int, err error) {
boring.Unreachable()
const (
// PSSSaltLengthAuto causes the salt in a PSS signature to be as large
// as possible when signing, and to be auto-detected when verifying.
+ //
+ // When signing in FIPS 140-3 mode, the salt length is capped at the length
+ // of the hash function used in the signature.
PSSSaltLengthAuto = 0
// PSSSaltLengthEqualsHash causes the salt length to equal the length
// of the hash used in the signature.
if fips140only.Enabled && !fips140only.ApprovedHash(hash.New()) {
return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
}
+ if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) {
+ return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
+ }
if opts != nil && opts.Hash != 0 {
hash = opts.Hash
if fips140only.Enabled && !fips140only.ApprovedHash(hash) {
return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode")
}
+ if fips140only.Enabled && !fips140only.ApprovedRandomReader(random) {
+ return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
+ }
defer hash.Reset()
if fips140only.Enabled && bits%2 == 1 {
return nil, errors.New("crypto/rsa: use of keys with odd size is not allowed in FIPS 140-only mode")
}
+ if fips140only.Enabled && !fips140only.ApprovedRandomReader(random) {
+ return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode")
+ }
k, err := rsa.GenerateKey(random, bits)
if err != nil {
"crypto"
"crypto/internal/boring"
"crypto/internal/cryptotest"
- "crypto/internal/fips140"
"crypto/rand"
. "crypto/rsa"
"crypto/sha1"
}
func TestEncryptOAEP(t *testing.T) {
- if fips140.Enabled {
- t.Skip("FIPS mode overrides the deterministic random source")
- }
sha1 := sha1.New()
n := new(big.Int)
for i, test := range testEncryptOAEPData {