{"record":{"id":"6af9a3d73b587e68","repo":"golang/go","slug":"crypto-rsa-p-is-even","errorCode":null,"errorMessage":"crypto/rsa: p is even","messagePattern":"crypto/rsa: p is even","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/crypto/internal/fips140/rsa/rsa.go","lineNumber":91,"sourceCode":"\tpMinusOne := p.Nat().SubOne(p)\n\tpMinusOneMod, err := bigmod.NewModulus(pMinusOne.Bytes(p))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdP := bigmod.NewNat().Mod(d, pMinusOneMod).Bytes(pMinusOneMod)\n\n\tqMinusOne := q.Nat().SubOne(q)\n\tqMinusOneMod, err := bigmod.NewModulus(qMinusOne.Bytes(q))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdQ := bigmod.NewNat().Mod(d, qMinusOneMod).Bytes(qMinusOneMod)\n\n\t// Constant-time modular inversion with prime modulus by Fermat's Little\n\t// Theorem: qInv = q⁻¹ mod p = q^(p-2) mod p.\n\tif p.Nat().IsOdd() == 0 {\n\t\t// [bigmod.Nat.Exp] requires an odd modulus.\n\t\treturn nil, errors.New(\"crypto/rsa: p is even\")\n\t}\n\tpMinusTwo := p.Nat().SubOne(p).SubOne(p).Bytes(p)\n\tqInv := bigmod.NewNat().Mod(q.Nat(), p)\n\tqInv.Exp(qInv, pMinusTwo, p)\n\n\tpk := &PrivateKey{\n\t\tpub: PublicKey{\n\t\t\tN: n, E: e,\n\t\t},\n\t\td: d, p: p, q: q,\n\t\tdP: dP, dQ: dQ, qInv: qInv,\n\t}\n\tif err := checkPrivateKey(pk); err != nil {\n\t\treturn nil, err\n\t}\n\treturn pk, nil\n}\n","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/rsa/rsa.go#L73-L109","documentation":"Thrown during RSA private-key construction when computing the CRT coefficient qInv = q^(p-2) mod p via Fermat's Little Theorem. bigmod.Nat.Exp requires an odd modulus, so if the prime factor p is even the exponentiation cannot proceed. A correct RSA prime is always odd, so this indicates a structurally malformed or corrupted key being assembled.","triggerScenarios":"Constructing/assembling an RSA PrivateKey in the fips140 package where the p factor is even (p.Nat().IsOdd() == 0). Reached during key generation finalization or when a manually-built key reaches the qInv computation step.","commonSituations":"Importing a key whose p was corrupted by a truncation/encoding bug. Feeding test fixtures with non-prime 'p' values. A broken RNG or prime-generation routine that produced an even candidate.","solutions":["Regenerate the key pair with rsa.GenerateKey / fips-approved generation rather than hand-assembling primes.","If importing primes, verify both p and q pass a primality test and IsOdd()==1 before constructing the PrivateKey.","Audit serialization/deserialization (PKCS#1, PEM) for byte-order or truncation errors that could zero the low bit of p."],"exampleFix":"// before\n// primes loaded from untrusted source, p may be even\npriv, err := buildPrivateKey(n, e, d, p, q)\n\n// after\nif p.Nat().IsOdd() == 0 || q.Nat().IsOdd() == 0 {\n    return errors.New(\"prime factor must be odd\")\n}\npriv, err := buildPrivateKey(n, e, d, p, q)","handlingStrategy":"validation","validationCode":"if p.Nat().IsOdd() == 0 {\n    return errors.New(\"reject even prime factor before key construction\")\n}","typeGuard":"func isOddPrimeFactor(p *bigmod.Nat) bool { return p.IsOdd() == 1 }","tryCatchPattern":"priv, err := buildOrImportKey(...)\nif err != nil {\n    if strings.Contains(err.Error(), \"p is even\") {\n        // key material corrupted; regenerate or re-import\n    }\n    return err\n}","preventionTips":["Always generate keys with rsa.GenerateKey rather than supplying primes manually.","When importing primes, assert both are odd and pass a primality test first.","Validate serialized keys round-trip through crypto/x509 parsers unchanged."],"tags":["crypto","rsa","key-generation","crt","go"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}