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
- Switch to hybrid encryption: encrypt a random 32-byte AES key with RSA, encrypt the payload with AES-GCM.
- If using RSA directly, ensure len(plaintext) <= k - 2*hashLen - 2 for OAEP (k = byte length of modulus).
- Use a larger RSA key only if absolutely necessary (e.g. 4096-bit) — but hybrid is almost always the right answer.
- 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
- Never RSA-encrypt arbitrary-size payloads; use RSA only to wrap a 32-byte symmetric key.
- Compute the OAEP budget (k - 2*hashLen - 2) up front and enforce it.
- Default to AES-GCM + RSA-OAEP hybrid for any non-trivial ciphertext.
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
- crypto/rsa: public exponent is even
- crypto/rsa: public exponent too large
- crypto/rsa: decryption error
- crypto/rsa: message too long for RSA key size
- crypto/rsa: unsupported hash function
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/bdfef4c820fc2045.
Report an issue: GitHub.