golang/go · critical
crypto/rsa: p is even
Error message
crypto/rsa: p is even
What it means
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.
Source
Thrown at src/crypto/internal/fips140/rsa/rsa.go:91
pMinusOne := p.Nat().SubOne(p)
pMinusOneMod, err := bigmod.NewModulus(pMinusOne.Bytes(p))
if err != nil {
return nil, err
}
dP := bigmod.NewNat().Mod(d, pMinusOneMod).Bytes(pMinusOneMod)
qMinusOne := q.Nat().SubOne(q)
qMinusOneMod, err := bigmod.NewModulus(qMinusOne.Bytes(q))
if err != nil {
return nil, err
}
dQ := bigmod.NewNat().Mod(d, qMinusOneMod).Bytes(qMinusOneMod)
// Constant-time modular inversion with prime modulus by Fermat's Little
// Theorem: qInv = q⁻¹ mod p = q^(p-2) mod p.
if p.Nat().IsOdd() == 0 {
// [bigmod.Nat.Exp] requires an odd modulus.
return nil, errors.New("crypto/rsa: p is even")
}
pMinusTwo := p.Nat().SubOne(p).SubOne(p).Bytes(p)
qInv := bigmod.NewNat().Mod(q.Nat(), p)
qInv.Exp(qInv, pMinusTwo, p)
pk := &PrivateKey{
pub: PublicKey{
N: n, E: e,
},
d: d, p: p, q: q,
dP: dP, dQ: dQ, qInv: qInv,
}
if err := checkPrivateKey(pk); err != nil {
return nil, err
}
return pk, nil
}
View on GitHub (pinned to b6b368adc5)
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.
Example fix
// before
// primes loaded from untrusted source, p may be even
priv, err := buildPrivateKey(n, e, d, p, q)
// after
if p.Nat().IsOdd() == 0 || q.Nat().IsOdd() == 0 {
return errors.New("prime factor must be odd")
}
priv, err := buildPrivateKey(n, e, d, p, q) Defensive patterns
Strategy: validation
Validate before calling
if p.Nat().IsOdd() == 0 {
return errors.New("reject even prime factor before key construction")
} Type guard
func isOddPrimeFactor(p *bigmod.Nat) bool { return p.IsOdd() == 1 } Try / catch
priv, err := buildOrImportKey(...)
if err != nil {
if strings.Contains(err.Error(), "p is even") {
// key material corrupted; regenerate or re-import
}
return err
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- crypto/rsa: invalid CRT exponent
- crypto/rsa: invalid CRT coefficient
- crypto/rsa: d does not match dP
- crypto/rsa: d does not match dQ
- rsa: key too small
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/6af9a3d73b587e68.
Report an issue: GitHub.