golang/go · error

crypto/ecdh: only crypto/rand.Reader is allowed in FIPS 140-

Error message

crypto/ecdh: only crypto/rand.Reader is allowed in FIPS 140-only mode

What it means

In FIPS 140-only mode, NIST-curve ECDH key generation must use crypto/rand.Reader specifically; any other io.Reader is rejected as a non-approved randomness source. The check runs after wiring the reader through rand.CustomReader, comparing against fips140only.ApprovedRandomReader.

Source

Thrown at src/crypto/ecdh/nist.go:51

			return nil, err
		}
		pub, err := key.PublicKey()
		if err != nil {
			return nil, err
		}
		k := &PrivateKey{
			curve:      c,
			privateKey: bytes,
			publicKey:  &PublicKey{curve: c, publicKey: pub.Bytes(), boring: pub},
			boring:     key,
		}
		return k, nil
	}

	r = rand.CustomReader(r)

	if fips140only.Enforced() && !fips140only.ApprovedRandomReader(r) {
		return nil, errors.New("crypto/ecdh: only crypto/rand.Reader is allowed in FIPS 140-only mode")
	}

	privateKey, err := c.generate(r)
	if err != nil {
		return nil, err
	}

	k := &PrivateKey{
		curve:      c,
		privateKey: privateKey.Bytes(),
		fips:       privateKey,
		publicKey: &PublicKey{
			curve:     c,
			publicKey: privateKey.PublicKey().Bytes(),
			fips:      privateKey.PublicKey(),
		},
	}
	if boring.Enabled {

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Pass crypto/rand.Reader (or nil where the API defaults to it) in FIPS builds.
  2. For tests, use testing/cryptotest.SetGlobalRandom instead of injecting a custom reader.
  3. Remove custom reader indirection in production FIPS paths.

Example fix

// before
priv, err := curve.GenerateKey(myTestReader) // fails in FIPS mode
// after
priv, err := curve.GenerateKey(rand.Reader)
Defensive patterns

Strategy: validation

Validate before calling

func genECDH(curve ecdh.Curve, r io.Reader) (*ecdh.PrivateKey, error) {
    if r == nil || (fipsEnabled() && !isApprovedReader(r)) {
        r = cryptoRand.Reader
    }
    return curve.GenerateKey(r)
}

Type guard

func isApprovedReader(r io.Reader) bool { return r == cryptoRand.Reader }

Try / catch

priv, err := curve.GenerateKey(r)
if err != nil && strings.Contains(err.Error(), "FIPS 140-only mode") {
    priv, err = curve.GenerateKey(cryptoRand.Reader)
}

Prevention

When it happens

Trigger: Calling ecdh.P256().GenerateKey(customReader) (or P384/P521) in a FIPS-only binary where customReader is not crypto/rand.Reader, e.g. a deterministic test reader or a custom entropy pool.

Common situations: Passing a seeded test reader in FIPS builds; using a hardware RNG wrapper that is not crypto/rand.Reader; code that abstracted randomness behind an interface.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/5e7b40204f06ad7c. Report an issue: GitHub.