golang/go · error

crypto/rsa: decryption error

Error message

crypto/rsa: decryption error

What it means

ErrDecryption is the deliberately generic error returned whenever an RSA private-key operation fails: wrong key, malformed ciphertext, or a PKCS#1 v1.5 / OAEP padding check failure. The message is intentionally vague to avoid leaking which sub-check failed and prevent Bleichenbacher-style padding-oracle attacks.

Source

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

// 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. Verify you are using the PrivateKey that corresponds (modulus-equal) to the PublicKey that encrypted.
  2. Confirm the exact same OAEP label, MGF hash, and primary hash are used on both sides.
  3. Re-check the ciphertext byte length equals the modulus byte length; re-examine base64/hex decoding on the wire.
  4. Treat the error as unauthenticated and do not branch user-visible behavior on it (do not distinguish 'wrong key' from 'corrupt').

Example fix

// before
pt, err := rsa.DecryptOAEP(sha256.New(), rand, priv, ct, []byte("wronglabel"))
// after
pt, err := rsa.DecryptOAEP(sha256.New(), rand, priv, ct, []byte("correctlabel"))
Defensive patterns

Strategy: try-catch

Validate before calling

if len(ciphertext) != (priv.N.BitLen()+7)/8 {
    return errors.New("ciphertext length does not match key size")
}

Try / catch

pt, err := rsa.DecryptOAEP(sha256.New(), rand, priv, ct, label)
if errors.Is(err, rsa.ErrDecryption) {
    // do NOT distinguish root cause; treat as auth failure
    return errors.New("decryption failed")
}

Prevention

When it happens

Trigger: Calling Decrypt (PKCS1v15 or OAEP) with: a ciphertext not produced by the matching public key; a ciphertext truncated/corrupted in transit; the wrong PrivateKey; random bytes; or a ciphertext encrypted under a different hash/MGF label than the decrypt side expects.

Common situations: Ciphertext base64-decoded with the wrong alphabet or padding; key rotation where the client still encrypts to the old public key; network framing bug that drops trailing bytes; OAEP label mismatch between encrypt and decrypt ends.

Related errors


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