golang/go · error

crypto/rsa: message too long for RSA key size

Error message

crypto/rsa: message too long for RSA key size

What it means

ErrMessageTooLong: the plaintext, interpreted as a big-endian unsigned integer, is greater than or equal to the modulus N. The encrypt path does bigmod.NewNat().SetBytes(plaintext, pub.N), which rejects any input whose byte length exceeds N's byte length (or whose value is >= N). Raw RSA can only encode a number strictly less than N.

Source

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

// Encrypt performs the RSA public key operation.
func Encrypt(pub *PublicKey, plaintext []byte) ([]byte, error) {
	fips140.RecordNonApproved()
	if _, err := checkPublicKey(pub); err != nil {
		return nil, err
	}
	return encrypt(pub, plaintext)
}

func encrypt(pub *PublicKey, plaintext []byte) ([]byte, error) {
	m, err := bigmod.NewNat().SetBytes(plaintext, pub.N)
	if err != nil {
		return nil, err
	}
	return bigmod.NewNat().ExpShortVarTime(m, uint(pub.E), pub.N).Bytes(pub.N), nil
}

var ErrMessageTooLong = errors.New("crypto/rsa: message too long for RSA key size")
var ErrDecryption = errors.New("crypto/rsa: decryption error")
var ErrVerification = errors.New("crypto/rsa: verification error")

const withCheck = true
const noCheck = false

// DecryptWithoutCheck performs the RSA private key operation.
func DecryptWithoutCheck(priv *PrivateKey, ciphertext []byte) ([]byte, error) {
	fips140.RecordNonApproved()
	return decrypt(priv, ciphertext, noCheck)
}

// DecryptWithCheck performs the RSA private key operation and checks the
// result to defend against errors in the CRT computation.
func DecryptWithCheck(priv *PrivateKey, ciphertext []byte) ([]byte, error) {
	fips140.RecordNonApproved()
	return decrypt(priv, ciphertext, withCheck)
}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Switch to hybrid encryption: encrypt a random 32-byte AES key with RSA, encrypt the payload with AES-GCM.
  2. If using RSA directly, ensure len(plaintext) <= k - 2*hashLen - 2 for OAEP (k = byte length of modulus).
  3. Use a larger RSA key only if absolutely necessary (e.g. 4096-bit) — but hybrid is almost always the right answer.
  4. Check len(plaintext) against the modulus byte length before calling Encrypt and return a clear application-level error.

Example fix

// before
ciphertext, err := rsa.EncryptOAEP(sha256.New(), rand, pub, largeBlob, nil)
// after
key := make([]byte, 32)
rand.Read(key)
wrapped, _ := rsa.EncryptOAEP(sha256.New(), rand, pub, key, nil)
ct := aesgcm.Seal(nil, nonce, largeBlob, nil) // AES-GCM
Defensive patterns

Strategy: validation

Validate before calling

k := (pub.N.BitLen() + 7) / 8 // modulus byte length
maxPlain := k - 2*sha256.Size - 2 // OAEP budget
if len(plaintext) > maxPlain {
    return errors.New("plaintext too long; use hybrid encryption")
}

Prevention

When it happens

Trigger: Calling fips140/rsa.Encrypt (or the higher-level rsa.EncryptOAEP / raw encrypt) with a plaintext byte slice that is too large for the key size. For a 2048-bit key the raw byte budget is 256 bytes; with OAEP it shrinks by 2*hashLen+2.

Common situations: Trying to RSA-encrypt a full document, JSON blob, or symmetric key that is too long; using a 1024-bit (legacy) key with a 128+ byte payload; forgetting that OAEP/SignerPKCS1v15 add padding overhead; passing a session ticket instead of just a 32-byte AES key.

Related errors


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