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
- Verify you are using the PrivateKey that corresponds (modulus-equal) to the PublicKey that encrypted.
- Confirm the exact same OAEP label, MGF hash, and primary hash are used on both sides.
- Re-check the ciphertext byte length equals the modulus byte length; re-examine base64/hex decoding on the wire.
- 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
- Verify the ciphertext length equals the modulus byte length before calling Decrypt.
- Ensure encrypt and decrypt use the identical OAEP label, MGF hash, and primary hash.
- Never branch user-visible behavior on ErrDecryption details — that is an oracle.
- Log decryption failures with a constant message and rate-limit the log.
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
- crypto/rsa: |p - q| too small
- crypto/rsa: d too small
- crypto/rsa: public modulus is even
- crypto/rsa: public exponent is even
- crypto/rsa: public exponent too large
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/9060530167e3f23b.
Report an issue: GitHub.