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
- Construct the RsaSecretEncryptor with a KeyPair (or private key / keystore alias containing the private key) so canDecrypt() returns true.
- If the encryptor intentionally holds only a public key, do not call decrypt — use a separate encryptor configured with the private key.
- 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
- Check canDecrypt() before any decrypt call.
- Build decrypt-side encryptors from a KeyPair or PrivateKeyEntry keystore alias.
- Keep encrypt-only (public key) encryptors separate from decrypt-capable ones by naming convention.
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
- Cannot decrypt
- Private key must be provided for decryption
- Unable to invoke Cipher due to bad padding
- Key data does not contain a public key
- key cannot be null
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/7212726084283b05.
Report an issue: GitHub.