{"record":{"id":"f78cff5a7886f18f","repo":"golang/go","slug":"crypto-rsa-invalid-crt-exponent","errorCode":null,"errorMessage":"crypto/rsa: invalid CRT exponent","messagePattern":"crypto/rsa: invalid CRT exponent","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/crypto/internal/fips140/rsa/rsa.go","lineNumber":243,"sourceCode":"\tif pN.Mul(qN, N).IsZero() != 1 {\n\t\treturn errors.New(\"crypto/rsa: p * q != n\")\n\t}\n\n\t// Check that de ≡ 1 mod p-1, and de ≡ 1 mod q-1.\n\t//\n\t// This implies that e is coprime to each p-1 as e has a multiplicative\n\t// inverse. Therefore e is coprime to lcm(p-1,q-1) = λ(N).\n\t// It also implies that a^de ≡ a mod p as a^(p-1) ≡ 1 mod p. Thus a^de ≡ a\n\t// mod n for all a coprime to n, as required.\n\t//\n\t// This checks dP, dQ, and e.\n\tpMinus1, err := bigmod.NewModulus(p.Nat().SubOne(p).Bytes(p))\n\tif err != nil {\n\t\treturn errors.New(\"crypto/rsa: invalid prime\")\n\t}\n\tdP, err := bigmod.NewNat().SetBytes(priv.dP, pMinus1)\n\tif err != nil {\n\t\treturn errors.New(\"crypto/rsa: invalid CRT exponent\")\n\t}\n\tde := bigmod.NewNat()\n\tde.SetUint(uint(priv.pub.E)).ExpandFor(pMinus1)\n\tde.Mul(dP, pMinus1)\n\tif de.IsOne() != 1 {\n\t\treturn errors.New(\"crypto/rsa: invalid CRT exponent\")\n\t}\n\n\tqMinus1, err := bigmod.NewModulus(q.Nat().SubOne(q).Bytes(q))\n\tif err != nil {\n\t\treturn errors.New(\"crypto/rsa: invalid prime\")\n\t}\n\tdQ, err := bigmod.NewNat().SetBytes(priv.dQ, qMinus1)\n\tif err != nil {\n\t\treturn errors.New(\"crypto/rsa: invalid CRT exponent\")\n\t}\n\tde.SetUint(uint(priv.pub.E)).ExpandFor(qMinus1)\n\tde.Mul(dQ, qMinus1)","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/rsa/rsa.go#L225-L261","documentation":"Thrown when SetBytes rejects priv.dP into the (p-1) modulus, meaning dP >= p-1 or its byte length is wrong. dP is d mod (p-1), a CRT exponent, and must be a valid residue in [0, p-1). An out-of-range dP means the stored CRT params are inconsistent with p.","triggerScenarios":"Key validation's CRT exponent check: dP does not fit modulus (p-1). Reached after the (p-1) modulus was successfully built.","commonSituations":"dP computed against a different p than the one stored (mismatched CRT params). dP byte slice truncated or extended during serialization. Key assembled from parts of different keys.","solutions":["Recompute dP = d mod (p-1) from the true d and p and overwrite the stored value, or re-import the full key.","Regenerate the key pair entirely.","Use a standard parser that round-trips all CRT fields atomically."],"exampleFix":"// before\n// dP loaded independently and inconsistent with p\n\n// after\npMinus1 := new(big.Int).Sub(p, big.NewInt(1))\ndP := new(big.Int).Mod(d, pMinus1)\n// store dP alongside the matching p","handlingStrategy":"validation","validationCode":"pMinus1 := new(big.Int).Sub(p, big.NewInt(1))\nif new(big.Int).Mod(dP, pMinus1).Cmp(dP) != 0 || dP.Cmp(pMinus1) >= 0 {\n    return errors.New(\"dP must be a valid residue mod (p-1)\")\n}","typeGuard":"func dPValidForP(dP, p *big.Int) bool {\n    pMinus1 := new(big.Int).Sub(p, big.NewInt(1))\n    return dP.Cmp(pMinus1) < 0\n}","tryCatchPattern":"err := validateKey(priv)\nif err != nil && strings.Contains(err.Error(), \"invalid CRT exponent\") {\n    // recompute dP from d and p, or regenerate\n    return err\n}","preventionTips":["Recompute dP = d mod (p-1) whenever p or d changes.","Keep all CRT fields atomic with the primes they were derived from.","Round-trip keys through standard PKCS#1 serialization."],"tags":["crypto","rsa","key-validation","crt","go"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}