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

  1. Regenerate the key pair with rsa.GenerateKey / fips-approved generation rather than hand-assembling primes.
  2. If importing primes, verify both p and q pass a primality test and IsOdd()==1 before constructing the PrivateKey.
  3. 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

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


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/6af9a3d73b587e68. Report an issue: GitHub.