spring-projects/spring-security · error · IllegalStateException

Cannot decrypt

Error message

Cannot decrypt

What it means

RsaRawEncryptor.decrypt(byte[]) wraps any checked Exception from the underlying RSA Cipher.doFinal into an IllegalStateException with message "Cannot decrypt", preserving the original as the cause. The library throws it when decryption of the raw ciphertext fails — typically a malformed/corrupt ciphertext block, a ciphertext longer than the modulus, or a key/algorithm mismatch between encrypt and decrypt.

Source

Thrown at crypto/src/main/java/org/springframework/security/crypto/encrypt/RsaRawEncryptor.java:163

		try {
			final Cipher cipher = Cipher.getInstance(alg.getJceName());
			int maxLength = getByteLength(key);
			int pos = 0;
			while (pos < text.length) {
				int limit = Math.min(text.length - pos, maxLength);
				cipher.init(Cipher.DECRYPT_MODE, key);
				cipher.update(text, pos, limit);
				pos += limit;
				byte[] buffer = cipher.doFinal();
				output.write(buffer, 0, buffer.length);
			}
			return output.toByteArray();
		}
		catch (RuntimeException ex) {
			throw ex;
		}
		catch (Exception ex) {
			throw new IllegalStateException("Cannot decrypt", ex);
		}
	}

	// copied from sun.security.rsa.RSACore.getByteLength(java.math.BigInteger)
	public static int getByteLength(@Nullable RSAKey key) {
		if (key == null) {
			throw new IllegalArgumentException("key cannot be null");
		}
		int n = key.getModulus().bitLength();
		return (n + 7) >> 3;
	}

}

View on GitHub (pinned to 96852e8860)

Solutions

  1. Ensure the byte array passed to decrypt is exactly the output of encrypt() with a matching key and algorithm — if you encoded with Base64, decode before decrypting.
  2. Verify the same RSAKeyPair/algorithm is used for both encryptor instances.
  3. Inspect the cause (ex.getCause()) — BadPaddingException/IllegalBlockSizeException indicate wrong key, wrong algorithm, or corrupted ciphertext.
  4. Regenerate test vectors by round-tripping through the same encryptor instance.

Example fix

// before
byte[] plain = encryptor.decrypt(encryptedBase64String.getBytes());
// after
byte[] cipherBytes = Base64.getDecoder().decode(encryptedBase64String);
byte[] plain = encryptor.decrypt(cipherBytes);
Defensive patterns

Strategy: try-catch

Validate before calling

// before decrypting
if (cipherBytes == null || cipherBytes.length == 0) throw new IllegalArgumentException("empty ciphertext");
if (cipherBytes.length != ((keyPair.getPublic().getModulus().bitLength() + 7) >> 3)) {
    throw new IllegalArgumentException("ciphertext length does not match RSA modulus");
}

Type guard

boolean isDecodable(RsaRawEncryptor enc, byte[] cipher, RSAKey key) {
    return cipher != null && cipher.length == RsaRawEncryptor.getByteLength(key);
}

Try / catch

try {
    byte[] plain = encryptor.decrypt(cipherBytes);
} catch (IllegalStateException ex) {
    logger.error("RSA decryption failed: " + ex.getCause(), ex);
    throw new SecurityException("Unable to decrypt payload", ex);
}

Prevention

When it happens

Trigger: Calling RsaRawEncryptor.decrypt(byte[]) with bytes not produced by encrypt(); ciphertext truncated or Base64-mangled; decrypting with a different RSA key or cipher algorithm (e.g. OAEP vs PKCS1) than used to encrypt; BadPaddingException from Cipher.doFinal.

Common situations: Passing a Base64 String's bytes directly instead of decoding first; encrypt/decrypt using keys of different sizes; data corrupted in transit or storage; switching between RsaRawEncryptor and RsaSecretEncryptor (different wire formats).

Related errors


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/490595374d72c7c1. Report an issue: GitHub.