{"record":{"id":"00b11c0286df1131","repo":"golang/go","slug":"crypto-rsa-p-q-n","errorCode":null,"errorMessage":"crypto/rsa: p * q != n","messagePattern":"crypto/rsa: p \\* q != n","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/crypto/internal/fips140/rsa/rsa.go","lineNumber":226,"sourceCode":"\tp := priv.p\n\tq := priv.q\n\n\t// FIPS 186-5, Section 5.1 requires \"that p and q be of the same bit length.\"\n\tif p.BitLen() != q.BitLen() {\n\t\tpriv.fipsApproved = false\n\t}\n\n\t// Check that pq ≡ 1 mod N (and that p < N and q < N).\n\tpN := bigmod.NewNat().ExpandFor(N)\n\tif _, err := pN.SetBytes(p.Nat().Bytes(p), N); err != nil {\n\t\treturn errors.New(\"crypto/rsa: invalid prime\")\n\t}\n\tqN := bigmod.NewNat().ExpandFor(N)\n\tif _, err := qN.SetBytes(q.Nat().Bytes(q), N); err != nil {\n\t\treturn errors.New(\"crypto/rsa: invalid prime\")\n\t}\n\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}","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/rsa/rsa.go#L208-L244","documentation":"Thrown when p*q mod N is zero, i.e. the product of the two stored primes is not equal to N. The check computes pN*qN mod N and expects a non-zero result (which for correctly-formed keys equals p*q, and since p*q = N < N^2 the residue is N itself, non-zero). A zero result proves N != p*q, so the modulus does not match its factors.","triggerScenarios":"Private-key consistency check where p and q are both < N (passed earlier guards) but their product is not N. Reached during GenerateKey self-check or explicit key validation.","commonSituations":"N was recomputed/edited independently of p,q. A key was assembled from mismatched p,q and N taken from different keys. Bit-flip corruption in N.","solutions":["Recompute N = p*q from the true primes and replace the stored N, or re-import the key wholesale.","Regenerate the key pair from scratch with rsa.GenerateKey.","Verify the key's integrity against its original source (HSM, keystore, PEM)."],"exampleFix":"// before\n// N loaded separately from p, q and they disagree\n\n// after\nexpectedN := new(big.Int).Mul(p, q)\nif expectedN.Cmp(n) != 0 {\n    return errors.New(\"N does not equal p*q\")\n}","handlingStrategy":"validation","validationCode":"expected := new(big.Int).Mul(p, q)\nif expected.Cmp(n) != 0 {\n    return errors.New(\"N must equal p*q\")\n}","typeGuard":"func modulusMatchesFactors(n, p, q *big.Int) bool {\n    return new(big.Int).Mul(p, q).Cmp(n) == 0\n}","tryCatchPattern":"err := validateKey(priv)\nif err != nil && strings.Contains(err.Error(), \"p * q != n\") {\n    // recompute N or regenerate; key is inconsistent\n    return err\n}","preventionTips":["Recompute N from p and q whenever either factor changes.","Never edit N independently of p and q.","Store and transport keys as opaque blobs parsed by standard libraries."],"tags":["crypto","rsa","key-validation","go"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}