spring-projects/spring-security · error · IllegalStateException
Unable to invoke Cipher due to bad padding
Error message
Unable to invoke Cipher due to bad padding
What it means
CipherUtils wraps JCE Cipher operations and rethrows checked exceptions as unchecked IllegalStateException. This error means Cipher.doFinal() threw BadPaddingException: the decrypted data's padding bytes did not match the padding scheme (e.g. PKCS5Padding) specified for the transform. It almost always indicates wrong key, corrupted/truncated ciphertext, or mismatched padding configuration between encryptor and decryptor.
Source
Thrown at crypto/src/main/java/org/springframework/security/crypto/encrypt/CipherUtils.java:144
}
catch (InvalidAlgorithmParameterException ex) {
throw new IllegalStateException("Unable to initialize due to invalid decryption parameter spec", ex);
}
}
/**
* Invokes the Cipher to perform encryption or decryption (depending on the
* initialized mode).
*/
static byte[] doFinal(Cipher cipher, byte[] input) {
try {
return cipher.doFinal(input);
}
catch (IllegalBlockSizeException ex) {
throw new IllegalStateException("Unable to invoke Cipher due to illegal block size", ex);
}
catch (BadPaddingException ex) {
throw new IllegalStateException("Unable to invoke Cipher due to bad padding", ex);
}
}
}
View on GitHub (pinned to 96852e8860)
Solutions
- Verify the decryptor uses the exact same password/key and transform as the encryptor
- Check the ciphertext string was not altered: compare byte length / Base64 integrity before decrypting
- Confirm the JCE provider supports the configured padding and unlimited-strength policy is available
- Wrap decryption in try-catch for IllegalStateException and treat as corrupt input rather than retrying
Example fix
// before
String plain = encryptor.decrypt(corruptedCipherText);
// after
try {
String plain = encryptor.decrypt(cipherText);
} catch (IllegalStateException ex) {
if (ex.getCause() instanceof BadPaddingException) {
throw new IOException("Ciphertext is corrupted or key mismatch", ex);
}
throw ex;
} Defensive patterns
Strategy: try-catch
Validate before calling
// verify ciphertext round-trips before relying on it
try {
decrypt(encrypt(sample));
} catch (IllegalStateException e) {
throw new IllegalArgumentException("Cipher transform/key mismatch", e);
} Try / catch
try { String plain = encryptor.decrypt(cipherText); } catch (IllegalStateException ex) { /* treat as corrupt input / key mismatch, do not retry */ } Prevention
- Always test encrypt->decrypt round trip after changing keys or transforms
- Never re-encode ciphertext through charset conversions or URL encoding
- Keep encryption keys versioned and identical across encrypting/decrypting services
- Log ciphertext length to detect truncation before decryption
When it happens
Trigger: Calling TextEncryptor/CipherUtils decrypt with a ciphertext produced by a different key, a different padding mode, or data that was truncated/re-encoded (e.g. Base64 mangled), so the final block fails the padding check.
Common situations: Rotated or mismatched encryption keys across environments; ciphertext round-tripped through a medium that altered bytes (URL encoding, charset conversion); decrypting data encrypted with a different provider or JCE policy (e.g. pre-JDK8 256-bit limits); switching transform from ECB/PKCS5 to CBC/NoPadding.
Related errors
- unable to encrypt/decrypt
- Not a valid encryption algorithm
- Unable to initialize due to invalid decryption parameter spe
- Cannot decrypt
- Encryptor is not configured for decryption
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/ebb47a428d0c9c72.
Report an issue: GitHub.