spring-projects/spring-security · error · IllegalArgumentException

saltGenerator cannot be null

Error message

saltGenerator cannot be null

What it means

The LdapShaPasswordEncoder(BytesKeyGenerator) constructor rejects a null saltGenerator with this IllegalArgumentException. The encoder needs a generator to produce random salt bytes for {SSHA} hashes (and salt comparison during matching), so a null generator would break both encode and matches. The no-arg constructor supplies KeyGenerators.secureRandom() automatically.

Source

Thrown at crypto/src/main/java/org/springframework/security/crypto/password/LdapShaPasswordEncoder.java:72

	private static final String SSHA_PREFIX = "{SSHA}";

	private static final String SSHA_PREFIX_LC = SSHA_PREFIX.toLowerCase(Locale.ENGLISH);

	private static final String SHA_PREFIX = "{SHA}";

	private static final String SHA_PREFIX_LC = SHA_PREFIX.toLowerCase(Locale.ENGLISH);

	private BytesKeyGenerator saltGenerator;

	private boolean forceLowerCasePrefix;

	public LdapShaPasswordEncoder() {
		this(KeyGenerators.secureRandom());
	}

	public LdapShaPasswordEncoder(BytesKeyGenerator saltGenerator) {
		if (saltGenerator == null) {
			throw new IllegalArgumentException("saltGenerator cannot be null");
		}
		this.saltGenerator = saltGenerator;
	}

	private byte[] combineHashAndSalt(byte[] hash, byte @Nullable [] salt) {
		if (salt == null) {
			return hash;
		}
		byte[] hashAndSalt = new byte[hash.length + salt.length];
		System.arraycopy(hash, 0, hashAndSalt, 0, hash.length);
		System.arraycopy(salt, 0, hashAndSalt, hash.length, salt.length);
		return hashAndSalt;
	}

	/**
	 * Calculates the hash of password (and salt bytes, if supplied) and returns a base64
	 * encoded concatenation of the hash and salt, prefixed with {SHA} (or {SSHA} if salt
	 * was used).

View on GitHub (pinned to 96852e8860)

Solutions

  1. Pass a real generator: new LdapShaPasswordEncoder(KeyGenerators.secureRandom()).
  2. Use the no-argument constructor LdapShaPasswordEncoder() which defaults to a secure random generator.
  3. Ensure any dependency-injected BytesKeyGenerator bean is actually defined and not null at construction time.

Example fix

// before
encoder = new LdapShaPasswordEncoder(saltGenerator); // null when bean missing
// after
encoder = new LdapShaPasswordEncoder(
    saltGenerator != null ? saltGenerator : KeyGenerators.secureRandom());
Defensive patterns

Strategy: type-guard

Type guard

BytesKeyGenerator safeGen = (gen != null) ? gen : KeyGenerators.secureRandom();
LdapShaPasswordEncoder encoder = new LdapShaPasswordEncoder(safeGen);

Try / catch

try {
    encoder = new LdapShaPasswordEncoder(saltGenerator);
} catch (IllegalArgumentException e) {
    encoder = new LdapShaPasswordEncoder(); // secureRandom default
}

Prevention

When it happens

Trigger: Directly invoking new LdapShaPasswordEncoder(null), e.g. passing a field or injected dependency that failed to initialize.

Common situations: Spring wiring where a salt generator bean is absent so the constructor argument resolves to null; code paths that conditionally build the encoder and skip generator creation.

Related errors


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