{"record":{"id":"867cf84aeb348de7","repo":"golang/go","slug":"crypto-ecdh-use-of-x25519-is-not-allowed-in-fips","errorCode":null,"errorMessage":"crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode","messagePattern":"crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/ecdh/x25519.go","lineNumber":39,"sourceCode":"\n// X25519 returns a [Curve] which implements the X25519 function over Curve25519\n// (RFC 7748, Section 5).\n//\n// Multiple invocations of this function will return the same value, so it can\n// be used for equality checks and switch statements.\nfunc X25519() Curve { return x25519 }\n\nvar x25519 = &x25519Curve{}\n\ntype x25519Curve struct{}\n\nfunc (c *x25519Curve) String() string {\n\treturn \"X25519\"\n}\n\nfunc (c *x25519Curve) GenerateKey(r io.Reader) (*PrivateKey, error) {\n\tif fips140only.Enforced() {\n\t\treturn nil, errors.New(\"crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode\")\n\t}\n\tr = rand.CustomReader(r)\n\tkey := make([]byte, x25519PrivateKeySize)\n\tif _, err := io.ReadFull(r, key); err != nil {\n\t\treturn nil, err\n\t}\n\treturn c.NewPrivateKey(key)\n}\n\nfunc (c *x25519Curve) NewPrivateKey(key []byte) (*PrivateKey, error) {\n\tif fips140only.Enforced() {\n\t\treturn nil, errors.New(\"crypto/ecdh: use of X25519 is not allowed in FIPS 140-only mode\")\n\t}\n\tif len(key) != x25519PrivateKeySize {\n\t\treturn nil, errors.New(\"crypto/ecdh: invalid private key size\")\n\t}\n\tpublicKey := make([]byte, x25519PublicKeySize)\n\tx25519Basepoint := [32]byte{9}","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/ecdh/x25519.go#L21-L57","documentation":"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.","triggerScenarios":"Calling ecdh.X25519().GenerateKey(rand.Reader) in a binary with FIPS 140-only enforcement enabled.","commonSituations":"Noise/Signal-style protocols or modern key-exchange code paths triggered inside a FIPS-regulated service; FIPS toolchain introduced by CI or deployment policy.","solutions":["Use a FIPS-approved NIST curve instead: ecdh.P256().GenerateKey(rand.Reader).","If FIPS-only is not required, rebuild without FIPS 140-only enforcement.","Isolate X25519 usage in a non-FIPS-only component if interop demands it (still non-compliant for the FIPS boundary)."],"exampleFix":"// before\npriv, err := ecdh.X25519().GenerateKey(rand.Reader)\n// after\npriv, err := ecdh.P256().GenerateKey(rand.Reader)","handlingStrategy":"fallback","validationCode":"func genKey(curve ecdh.Curve, rand io.Reader) (*ecdh.PrivateKey, error) {\n    if fipsEnabled() {\n        curve = ecdh.P256() // X25519 not approved under FIPS\n    }\n    return curve.GenerateKey(rand)\n}","typeGuard":null,"tryCatchPattern":"priv, err := ecdh.X25519().GenerateKey(rand.Reader)\nif err != nil && strings.Contains(err.Error(), \"FIPS 140-only mode\") {\n    priv, err = ecdh.P256().GenerateKey(rand.Reader)\n}","preventionTips":["Do not invoke X25519 in FIPS-only builds; use a NIST curve.","Negotiate the curve in the protocol so peers align on an approved curve.","Document curve availability per deployment mode."],"tags":["crypto","ecdh","x25519","fips","compliance","go","security"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}