spring-projects/spring-security · error · IllegalStateException

Cannot decrypt

Error message

Cannot decrypt

What it means

RsaSecretEncryptor.decrypt wraps any non-RuntimeException thrown during RSA decryption (JCE Cipher/BadPadding/IllegalBlockSizeException etc.) in an IllegalStateException with the message 'Cannot decrypt'. The library throws it because the input could not be decrypted with the configured RSA key — typically wrong key, corrupted/ciphertext mismatch, or a cipher operation failure. It deliberately preserves the original exception as the cause.

Source

Thrown at crypto/src/main/java/org/springframework/security/crypto/encrypt/RsaSecretEncryptor.java:234

		ByteArrayOutputStream output = new ByteArrayOutputStream(text.length);
		try {
			int length = readInt(input);
			byte[] random = new byte[length];
			input.read(random);
			final Cipher cipher = Cipher.getInstance(alg.getJceName());
			cipher.init(Cipher.DECRYPT_MODE, key);
			String secret = new String(Hex.encode(cipher.doFinal(random)));
			byte[] buffer = new byte[text.length - random.length - 2];
			input.read(buffer);
			BytesEncryptor aes = gcm ? Encryptors.stronger(secret, salt) : Encryptors.standard(secret, salt);
			output.write(aes.decrypt(buffer));
			return output.toByteArray();
		}
		catch (RuntimeException ex) {
			throw ex;
		}
		catch (Exception ex) {
			throw new IllegalStateException("Cannot decrypt", ex);
		}
	}

	private static boolean isHex(String input) {
		try {
			Hex.decode(input);
			return true;
		}
		catch (Exception ex) {
			return false;
		}
	}

	public boolean canDecrypt() {
		return this.privateKey != null;
	}

}

View on GitHub (pinned to 96852e8860)

Solutions

  1. Ensure decryption uses the exact same RsaSecretEncryptor/key pair that produced the ciphertext (same keystore, alias, and key).
  2. Verify the input is the raw ciphertext in the form the encryptor expects (bytes, not re-encoded hex/base64 unless matching how it was encrypted).
  3. Check that encrypt/decrypt use the same algorithm configuration; mixed-algorithm round trips fail by design (public key cannot decrypt its own output).
  4. Catch IllegalStateException and inspect getCause() to distinguish BadPadding/IllegalBlockSize (wrong key/data) from other failures.
  5. If keys were rotated, re-encrypt data with the new key before discarding the old one.

Example fix

// before
String plain = new String(encryptor.decrypt(cipherText));
// after
try {
    String plain = new String(encryptor.decrypt(cipherText));
} catch (IllegalStateException ex) {
    // ex.getCause() is the JCE failure: usually wrong key or corrupt ciphertext
    throw new DecryptionException("Ciphertext not decryptable with configured RSA key", ex);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Before decrypting, confirm you hold the same encryptor/key that encrypted the data
if (ciphertext == null || ciphertext.length == 0) {
    throw new IllegalArgumentException("no ciphertext to decrypt");
}
// If ciphertext was stored as text, decode it exactly as it was encoded on write (hex vs base64)

Type guard

boolean canDecrypt(RsaSecretEncryptor e, byte[] stored, byte[] probe) {
    try { e.decrypt(e.encrypt(new byte[0])); return true; } catch (Exception ex) { return false; }
}

Try / catch

try {
    byte[] plain = encryptor.decrypt(ciphertext);
} catch (IllegalStateException ex) {
    // cause is the JCE failure (wrong key / corrupt data)
    logger.warn("Decryption failed: {}", ex.getCause() == null ? ex.getMessage() : ex.getCause().toString());
    throw new DecryptionException(ex);
}

Prevention

When it happens

Trigger: Calling decrypt() on ciphertext produced with a different key or algorithm; RSA cipher failure such as BadPaddingException/IllegalBlockSizeException because the data is not valid RSA ciphertext for this encryptor; using an encryptor whose key pair does not match the one used to encrypt; decryption path taken when the input was actually encrypted with the public-key-only mode or vice versa (see tests roundTripWithMixedAlgorithm, roundTripWithPublicKeyEncryption, publicKeyCannotDecrypt).

Common situations: Rotating or regenerating the keystore/KeyPair while old ciphertexts remain in the database; sharing ciphertext between environments with different keys; decrypting base64/hex-decoded data that was encrypted by another library or algorithm; a keystore alias pointing to the wrong private key.

Related errors


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