spring-projects/spring-security · error · IllegalArgumentException

ivGenerator key length != block size 16

Error message

ivGenerator key length != block size 16

What it means

BouncyCastleAesBytesEncryptor uses a per-message IV equal in length to the AES block size (16 bytes). The constructor validates that the supplied ivGenerator produces exactly 16-byte keys and throws IllegalArgumentException otherwise, since any other IV length breaks CBC/GCM block processing.

Source

Thrown at crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesBytesEncryptor.java:45

/**
 * Base class for AES-256 encryption using Bouncy Castle.
 *
 * @author William Tran
 *
 */
abstract class BouncyCastleAesBytesEncryptor implements BytesEncryptor {

	final KeyParameter secretKey;

	final BytesKeyGenerator ivGenerator;

	BouncyCastleAesBytesEncryptor(String password, CharSequence salt) {
		this(password, salt, KeyGenerators.secureRandom(16));
	}

	BouncyCastleAesBytesEncryptor(String password, CharSequence salt, BytesKeyGenerator ivGenerator) {
		if (ivGenerator.getKeyLength() != 16) {
			throw new IllegalArgumentException("ivGenerator key length != block size 16");
		}
		this.ivGenerator = ivGenerator;
		PBEParametersGenerator keyGenerator = new PKCS5S2ParametersGenerator();
		byte[] pkcs12PasswordBytes = PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(password.toCharArray());
		keyGenerator.init(pkcs12PasswordBytes, Hex.decode(salt), 1024);
		this.secretKey = (KeyParameter) keyGenerator.generateDerivedParameters(256);
	}

}

View on GitHub (pinned to 96852e8860)

Solutions

  1. Pass KeyGenerators.secureRandom(16) as the ivGenerator.
  2. Verify the generator's getKeyLength() equals 16 before constructing.
  3. Use the two-arg constructor BouncyCastleAesBytesEncryptor(password, salt), which defaults to a correct 16-byte secure random generator.

Example fix

// before
BytesKeyGenerator ivGen = KeyGenerators.secureRandom(32);
BytesEncryptor e = new BouncyCastleAesBytesEncryptor(password, salt, ivGen); // throws
// after
BytesEncryptor e = new BouncyCastleAesBytesEncryptor(password, salt, KeyGenerators.secureRandom(16));
Defensive patterns

Strategy: validation

Validate before calling

if (ivGenerator.getKeyLength() != 16) throw new IllegalStateException("ivGenerator must produce 16-byte IVs");

Try / catch

try { encryptor = new BouncyCastleAesBytesEncryptor(password, salt, ivGen); } catch (IllegalArgumentException e) { encryptor = new BouncyCastleAesBytesEncryptor(password, salt); }

Prevention

When it happens

Trigger: new BouncyCastleAesBytesEncryptor(password, salt, ivGenerator) where ivGenerator.getKeyLength() != 16, e.g. KeyGenerators.secureRandom(8), a 32-byte generator, or a custom generator with shared(16)-style fixed but wrong-length keys.

Common situations: Reusing an IV generator configured for a different cipher (e.g. 8-byte for DES); misreading 'key length' docs and passing a generator sized for the AES key (32) rather than the block; refactors that share one generator constant across encryptors.

Related errors


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