spring-projects/spring-security · error · IllegalStateException

Unable to invoke Cipher due to illegal block size

Error message

Unable to invoke Cipher due to illegal block size

What it means

Thrown by CipherUtils.doFinal when cipher.doFinal(input) throws IllegalBlockSizeException. The input length is not a valid multiple of the cipher's block size (typical for a no-padding block cipher) or the cipher is in a state (e.g. already finalized) that forbids processing more data.

Source

Thrown at crypto/src/main/java/org/springframework/security/crypto/encrypt/CipherUtils.java:141

		}
		catch (InvalidKeyException ex) {
			throw new IllegalArgumentException("Unable to initialize due to invalid secret key", ex);
		}
		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

  1. Use a padding mode (e.g. "AES/CBC/PKCS5Padding") or pad input to a multiple of 16 bytes yourself when using NoPadding.
  2. Create a fresh Cipher per encrypt/decrypt operation rather than reusing a finalized instance.
  3. Verify ciphertext is stored/retrieved in full (check column types are VARBINARY/BLOB or Base64 text, not lossy CHAR columns).
  4. Confirm encrypt and decrypt use the same transformation string.

Example fix

// before
Cipher cipher = CipherUtils.newCipher("AES/CBC/NoPadding");
byte[] out = CipherUtils.doFinal(cipher, twentyByteArray); // not a multiple of 16
// after
Cipher cipher = CipherUtils.newCipher("AES/CBC/PKCS5Padding");
byte[] out = CipherUtils.doFinal(cipher, input); // any length OK with padding
Defensive patterns

Strategy: validation

Validate before calling

if (input == null || input.length % 16 != 0) {
    throw new IllegalArgumentException("NoPadding ciphers require input length multiple of 16 bytes");
}

Try / catch

try {
    return CipherUtils.doFinal(cipher, input);
} catch (IllegalStateException ex) {
    throw new DataCorruptionException("Cipher doFinal failed (block size/state) — check padding mode and ciphertext integrity", ex);
}

Prevention

When it happens

Trigger: Using a transformation with NoPadding and passing input whose length isn't a block-size multiple (e.g. 20 bytes to AES with no padding); calling doFinal twice on the same Cipher instance; corrupting/truncating ciphertext so the final block is incomplete.

Common situations: Custom encryptors configured with "AES/CBC/NoPadding"; reusing a Cipher object across calls instead of creating a new one per operation; storage layers that truncate binary columns or strip trailing bytes from ciphertext.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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