golang/go · error

crypto/ecdh: use of X25519 is not allowed in FIPS 140-only m

Error message

crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode

What it means

In FIPS 140-only mode, X25519 key generation is refused because X25519 is not in the FIPS-approved algorithm set (it is a CFRG curve, not a NIST/FIPS curve). The check is the first statement in x25519Curve.GenerateKey.

Source

Thrown at src/crypto/ecdh/x25519.go:39

// X25519 returns a [Curve] which implements the X25519 function over Curve25519
// (RFC 7748, Section 5).
//
// Multiple invocations of this function will return the same value, so it can
// be used for equality checks and switch statements.
func X25519() Curve { return x25519 }

var x25519 = &x25519Curve{}

type x25519Curve struct{}

func (c *x25519Curve) String() string {
	return "X25519"
}

func (c *x25519Curve) GenerateKey(r io.Reader) (*PrivateKey, error) {
	if fips140only.Enforced() {
		return nil, errors.New("crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode")
	}
	r = rand.CustomReader(r)
	key := make([]byte, x25519PrivateKeySize)
	if _, err := io.ReadFull(r, key); err != nil {
		return nil, err
	}
	return c.NewPrivateKey(key)
}

func (c *x25519Curve) NewPrivateKey(key []byte) (*PrivateKey, error) {
	if fips140only.Enforced() {
		return nil, errors.New("crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode")
	}
	if len(key) != x25519PrivateKeySize {
		return nil, errors.New("crypto/ecdh: invalid private key size")
	}
	publicKey := make([]byte, x25519PublicKeySize)
	x25519Basepoint := [32]byte{9}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Use a FIPS-approved NIST curve instead: ecdh.P256().GenerateKey(rand.Reader).
  2. If FIPS-only is not required, rebuild without FIPS 140-only enforcement.
  3. Isolate X25519 usage in a non-FIPS-only component if interop demands it (still non-compliant for the FIPS boundary).

Example fix

// before
priv, err := ecdh.X25519().GenerateKey(rand.Reader)
// after
priv, err := ecdh.P256().GenerateKey(rand.Reader)
Defensive patterns

Strategy: fallback

Validate before calling

func genKey(curve ecdh.Curve, rand io.Reader) (*ecdh.PrivateKey, error) {
    if fipsEnabled() {
        curve = ecdh.P256() // X25519 not approved under FIPS
    }
    return curve.GenerateKey(rand)
}

Try / catch

priv, err := ecdh.X25519().GenerateKey(rand.Reader)
if err != nil && strings.Contains(err.Error(), "FIPS 140-only mode") {
    priv, err = ecdh.P256().GenerateKey(rand.Reader)
}

Prevention

When it happens

Trigger: Calling ecdh.X25519().GenerateKey(rand.Reader) in a binary with FIPS 140-only enforcement enabled.

Common situations: Noise/Signal-style protocols or modern key-exchange code paths triggered inside a FIPS-regulated service; FIPS toolchain introduced by CI or deployment policy.

Related errors


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