golang/go · error

crypto/rsa: public exponent too small or negative

Error message

crypto/rsa: public exponent too small or negative

What it means

Thrown by checkPublicKey when the public exponent E < 2. The exponent must be an odd integer >= 3 to be invertible modulo λ(N) (E=1 makes every signature/message identical, E<=0 is meaningless). This guard rejects degenerate exponents before checking oddness and the FIPS bounds (2^16 < e < 2^256).

Source

Thrown at src/crypto/internal/fips140/rsa/rsa.go:344

func checkPublicKey(pub *PublicKey) (fipsApproved bool, err error) {
	fipsApproved = true
	if pub.N == nil {
		return false, errors.New("crypto/rsa: missing public modulus")
	}
	if pub.N.Nat().IsOdd() == 0 {
		return false, errors.New("crypto/rsa: public modulus is even")
	}
	// FIPS 186-5, Section 5.1: "This standard specifies the use of a modulus
	// whose bit length is an even integer and greater than or equal to 2048
	// bits."
	if pub.N.BitLen() < 2048 {
		fipsApproved = false
	}
	if pub.N.BitLen()%2 == 1 {
		fipsApproved = false
	}
	if pub.E < 2 {
		return false, errors.New("crypto/rsa: public exponent too small or negative")
	}
	// e needs to be coprime with p-1 and q-1, since it must be invertible
	// modulo λ(pq). Since p and q are prime, this means e needs to be odd.
	if pub.E&1 == 0 {
		return false, errors.New("crypto/rsa: public exponent is even")
	}
	// FIPS 186-5, Section 5.5(e): "The exponent e shall be an odd, positive
	// integer such that 2¹⁶ < e < 2²⁵⁶."
	if pub.E <= 1<<16 {
		fipsApproved = false
	}
	// We require pub.E to fit into a 32-bit integer so that we
	// do not have different behavior depending on whether
	// int is 32 or 64 bits. See also
	// https://www.imperialviolet.org/2012/03/16/rsae.html.
	if pub.E > 1<<31-1 {
		return false, errors.New("crypto/rsa: public exponent too large")
	}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Set E to 65537 (the conventional value) when constructing the PublicKey, or parse it via x509.
  2. Guard with an E >= 3 and odd check before any RSA operation.
  3. Regenerate the key pair; rsa.GenerateKey sets E = 65537 by default.

Example fix

// before
pub := &rsa.PublicKey{N: n} // E zero-valued to 0

// after
pub := &rsa.PublicKey{N: n, E: 65537}
if pub.E < 3 || pub.E&1 == 0 {
    return errors.New("invalid RSA public exponent")
}
Defensive patterns

Strategy: validation

Validate before calling

if pub.E < 3 || pub.E&1 == 0 {
    return fmt.Errorf("invalid RSA public exponent: %d", pub.E)
}

Type guard

func validPublicExponent(e int) bool { return e >= 3 && e&1 == 1 }

Try / catch

err := op(pub)
if err != nil && strings.Contains(err.Error(), "public exponent too small or negative") {
    return err // set E = 65537 or regenerate
}

Prevention

When it happens

Trigger: checkPublicKey tests pub.E < 2 during any RSA operation that validates the public key. Fires for E = 0, 1, or negative values.

Common situations: A zero-value rsa.PublicKey with E == 0 used before population. A parse failure that left E unset. A custom builder that copied the wrong field into E. Negative E from a signed-int conversion bug.

Related errors


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