{"record":{"id":"50d4be2628198b5e","repo":"golang/go","slug":"crypto-rsa-invalid-crt-coefficient","errorCode":null,"errorMessage":"crypto/rsa: invalid CRT coefficient","messagePattern":"crypto/rsa: invalid CRT coefficient","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/crypto/internal/fips140/rsa/rsa.go","lineNumber":273,"sourceCode":"\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)\n\tif de.IsOne() != 1 {\n\t\treturn errors.New(\"crypto/rsa: invalid CRT exponent\")\n\t}\n\n\t// Check that qInv * q ≡ 1 mod p.\n\tqP, err := bigmod.NewNat().SetOverflowingBytes(q.Nat().Bytes(q), p)\n\tif err != nil {\n\t\t// q >= 2^⌈log2(p)⌉\n\t\tqP = bigmod.NewNat().Mod(q.Nat(), p)\n\t}\n\tif qP.Mul(priv.qInv, p).IsOne() != 1 {\n\t\treturn errors.New(\"crypto/rsa: invalid CRT coefficient\")\n\t}\n\n\t// Check d against dP and dQ, even though we never actually use d,\n\t// to make sure the key is consistent.\n\tdP1 := bigmod.NewNat().Mod(priv.d, pMinus1)\n\tif dP1.Equal(dP) != 1 {\n\t\treturn errors.New(\"crypto/rsa: d does not match dP\")\n\t}\n\tdQ1 := bigmod.NewNat().Mod(priv.d, qMinus1)\n\tif dQ1.Equal(dQ) != 1 {\n\t\treturn errors.New(\"crypto/rsa: d does not match dQ\")\n\t}\n\n\t// Check that |p - q| > 2^(nlen/2 - 100).\n\t//\n\t// If p and q are very close to each other, then N=pq can be trivially\n\t// factored using Fermat's factorization method. Broken RSA implementations\n\t// do generate such keys. See Hanno Böck, Fermat Factorization in the Wild,","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/rsa/rsa.go#L255-L291","documentation":"Thrown when qInv * q mod p != 1, i.e. qInv is not the modular inverse of q modulo p. qInv is the CRT coefficient used to recombine the p-side and q-side results; if it does not satisfy q*qInv ≡ 1 mod p, CRT decryption/signing would produce wrong outputs. The check computes qP = q mod p then tests qP.Mul(qInv, p).IsOne().","triggerScenarios":"Key validation's CRT coefficient check fails: qP * qInv mod p is not 1. Reached after both CRT exponent checks passed.","commonSituations":"qInv computed against a different p (e.g. p and q swapped after qInv was derived). qInv byte-corrupted. Key assembled from mismatched sources.","solutions":["Recompute qInv = q^{-1} mod p (via q^(p-2) mod p for odd prime p) from consistent p and q.","Ensure p and q are in the same order used during qInv derivation.","Regenerate the key to guarantee a consistent CRT coefficient."],"exampleFix":"// before\n// qInv from a key where p and q were later swapped\n\n// after\nqInv := new(big.Int).ModInverse(q, p) // requires Go 1.20+ math/big","handlingStrategy":"validation","validationCode":"check := new(big.Int).Mul(q, qInv)\ncheck.Mod(check, p)\nif check.Cmp(big.NewInt(1)) != 0 {\n    return errors.New(\"q*qInv != 1 mod p\")\n}","typeGuard":"func qInvCorrect(qInv, q, p *big.Int) bool {\n    return new(big.Int).Mod(new(big.Int).Mul(q, qInv), p).Cmp(big.NewInt(1)) == 0\n}","tryCatchPattern":"err := validateKey(priv)\nif err != nil && strings.Contains(err.Error(), \"invalid CRT coefficient\") {\n    return err // recompute qInv = q^{-1} mod p\n}","preventionTips":["Keep p and q in the order used when qInv was derived.","Recompute qInv whenever p or q changes.","Use math/big ModInverse (or Fermat exp) from consistent primes."],"tags":["crypto","rsa","key-validation","crt","go"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:17:08.281Z"}