spring-projects/spring-security · error · IllegalStateException

Encryptor is not configured for decryption

Error message

Encryptor is not configured for decryption

What it means

RsaSecretEncryptor.decrypt(String) checks canDecrypt() and throws IllegalStateException("Encryptor is not configured for decryption") when the encryptor was created with only a public key, so it has no PrivateKey to perform decryption. This is a fail-fast guard before Base64 decoding and RSA decryption.

Source

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

		this.algorithm = algorithm;
		this.salt = isHex(salt) ? salt : new String(Hex.encode(salt.getBytes(this.defaultCharset)));
		this.gcm = gcm;
	}

	@Override
	public String getPublicKey() {
		return RsaKeyHelper.encodePublicKey((RSAPublicKey) this.publicKey, "application");
	}

	@Override
	public String encrypt(String text) {
		return new String(Base64.getEncoder().encode(encrypt(text.getBytes(this.charset))), this.defaultCharset);
	}

	@Override
	public String decrypt(String encryptedText) {
		if (!canDecrypt()) {
			throw new IllegalStateException("Encryptor is not configured for decryption");
		}
		return new String(decrypt(Base64.getDecoder().decode(encryptedText.getBytes(this.defaultCharset))),
				this.charset);
	}

	@Override
	public byte[] encrypt(byte[] byteArray) {
		return encrypt(byteArray, this.publicKey, this.algorithm, this.salt, this.gcm);
	}

	@Override
	public byte[] decrypt(byte[] encryptedByteArray) {
		if (!canDecrypt()) {
			throw new IllegalStateException("Encryptor is not configured for decryption");
		}
		return decrypt(encryptedByteArray, this.privateKey, this.algorithm, this.salt, this.gcm);
	}

View on GitHub (pinned to 96852e8860)

Solutions

  1. Construct the RsaSecretEncryptor with a KeyPair (or private key / keystore alias containing the private key) so canDecrypt() returns true.
  2. If the encryptor intentionally holds only a public key, do not call decrypt — use a separate encryptor configured with the private key.
  3. Check canDecrypt() before calling decrypt and route to an encryptor that has the private key.

Example fix

// before
RsaSecretEncryptor enc = new RsaSecretEncryptor(publicKey);
String plain = enc.decrypt(cipherText); // throws
// after
RsaSecretEncryptor dec = new RsaSecretEncryptor(keyPair); // has private key
String plain = dec.decrypt(cipherText);
Defensive patterns

Strategy: validation

Validate before calling

if (!encryptor.canDecrypt()) {
    throw new UnsupportedOperationException("This encryptor holds only a public key; use a private-key-configured encryptor to decrypt");
}
String plain = encryptor.decrypt(encryptedText);

Type guard

boolean canDecrypt(RsaSecretEncryptor enc) { return enc != null && enc.canDecrypt(); }

Try / catch

try {
    return encryptor.decrypt(encryptedText);
} catch (IllegalStateException ex) {
    if (ex.getMessage().contains("not configured for decryption")) {
        return privateKeyEncryptor.decrypt(encryptedText);
    }
    throw ex;
}

Prevention

When it happens

Trigger: Creating an RsaSecretEncryptor from a public key only (or a KeyStore entry exposing only the certificate/public key) and then calling decrypt(String); hybrid mode where only publicKey was provided.

Common situations: Server-side encryptor built with a partner's public key that should never decrypt; loading a keystore alias that only contains a certificate; unit test publicKeyCannotDecrypt asserting this behavior.

Related errors


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