{"record":{"id":"8d04681cd4663164","repo":"golang/go","slug":"crypto-rsa-p-q","errorCode":null,"errorMessage":"crypto/rsa: p == q","messagePattern":"crypto/rsa: p == q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/crypto/internal/fips140/rsa/rsa.go","lineNumber":298,"sourceCode":"\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,\n\t// https://eprint.iacr.org/2023/026.pdf.\n\tdiff := bigmod.NewNat()\n\tif qP, err := bigmod.NewNat().SetBytes(q.Nat().Bytes(q), p); err != nil {\n\t\t// q > p\n\t\tpQ, err := bigmod.NewNat().SetBytes(p.Nat().Bytes(p), q)\n\t\tif err != nil {\n\t\t\treturn errors.New(\"crypto/rsa: p == q\")\n\t\t}\n\t\t// diff = 0 - p mod q = q - p\n\t\tdiff.ExpandFor(q).Sub(pQ, q)\n\t} else {\n\t\t// p > q\n\t\t// diff = 0 - q mod p = p - q\n\t\tdiff.ExpandFor(p).Sub(qP, p)\n\t}\n\t// A tiny bit of leakage is acceptable because it's not adaptive, an\n\t// attacker only learns the magnitude of p - q.\n\tif diff.BitLenVarTime() <= N.BitLen()/2-100 {\n\t\treturn errors.New(\"crypto/rsa: |p - q| too small\")\n\t}\n\n\t// Check that d > 2^(nlen/2).\n\t//\n\t// See section 3 of https://crypto.stanford.edu/~dabo/papers/RSA-survey.pdf\n\t// for more details about attacks on small d values.","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/rsa/rsa.go#L280-L316","documentation":"Thrown when computing |p - q| and both directions of SetBytes fail, which happens when p == q (neither fits into the other's modulus because they are equal and each equals the modulus of itself). Distinct primes are mandatory for RSA; identical factors make N = p^2 trivially factorable.","triggerScenarios":"The |p-q| Fermat-protection check: qP = SetBytes(q, p) fails, then pQ = SetBytes(p, q) also fails, indicating p == q. Reached during key validation after all CRT checks passed.","commonSituations":"A key generator that duplicated p into q. A test fixture that reuses the same prime twice. Manual key assembly that assigned p to both fields.","solutions":["Regenerate the key with a generator that draws p and q independently.","On import, reject keys where p.Cmp(q) == 0 before the fips path.","Audit custom prime-generation code to ensure q is a fresh draw, not a copy of p."],"exampleFix":"// before\n// q accidentally set equal to p\n\n// after\nif p.Cmp(q) == 0 {\n    return errors.New(\"p and q must be distinct primes\")\n}","handlingStrategy":"validation","validationCode":"if p.Cmp(q) == 0 {\n    return errors.New(\"p and q must be distinct\")\n}","typeGuard":"func primesDistinct(p, q *big.Int) bool { return p.Cmp(q) != 0 }","tryCatchPattern":"err := validateKey(priv)\nif err != nil && strings.Contains(err.Error(), \"p == q\") {\n    return err // regenerate with distinct primes\n}","preventionTips":["Generate p and q with independent randomness draws.","On import, reject p == q immediately.","Audit custom generators to ensure q is not a copy of p."],"tags":["crypto","rsa","key-validation","go"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}