spring-projects/spring-security · error · IllegalStateException
Private key must be provided for decryption
Error message
Private key must be provided for decryption
What it means
RsaRawEncryptor.decrypt(String) requires an RSA private key to perform decryption. The encryptor was constructed without one (privateKey == null), so the method refuses to run and throws this IllegalStateException.
Source
Thrown at crypto/src/main/java/org/springframework/security/crypto/encrypt/RsaRawEncryptor.java:103
this.privateKey = (RSAPrivateKey) privateKey;
this.defaultCharset = Charset.forName(DEFAULT_ENCODING);
this.algorithm = algorithm;
}
@Override
public String getPublicKey() {
return RsaKeyHelper.encodePublicKey(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 (this.privateKey == null) {
throw new IllegalStateException("Private key must be provided 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);
}
@Override
public byte[] decrypt(byte[] encryptedByteArray) {
return decrypt(encryptedByteArray, this.privateKey, this.algorithm);
}
private static byte[] encrypt(byte[] text, PublicKey key, RsaAlgorithm alg) {
ByteArrayOutputStream output = new ByteArrayOutputStream(text.length);
try {View on GitHub (pinned to 96852e8860)
Solutions
- Construct the encryptor with an RSAPrivateKey (e.g. load from PEM/PKCS#8 keystore) before decrypting.
- Ensure key-loading code does not swallow exceptions and fall back to null.
- Use separate encryptor instances: public-key encryptor for encrypt, private-key decryptor for decrypt.
- Add a startup validation that the private key is present when decryption is required.
Example fix
// before
RsaRawEncryptor e = new RsaRawEncryptor(publicKey);
String plain = e.decrypt(cipher); // IllegalStateException
// after
RSAPrivateKey priv = loadPrivateKey("keystore.p12", "pass");
RsaRawEncryptor e = new RsaRawEncryptor(publicKey, priv);
String plain = e.decrypt(cipher); Defensive patterns
Strategy: try-catch
Validate before calling
Objects.requireNonNull(privateKey, "RSAPrivateKey required for decryption");
Type guard
boolean canDecrypt(RsaRawEncryptor e, RSAPrivateKey configured) {
return configured != null;
} Try / catch
try {
return encryptor.decrypt(encryptedText);
} catch (IllegalStateException e) {
if (e.getMessage().contains("Private key must be provided")) {
throw new ConfigException("No private key configured for RsaRawEncryptor decryption");
}
throw e;
} Prevention
- Construct encryptors used for decryption with both keys or a private-key-only constructor.
- Fail at startup if privateKey loading returned null.
- Separate encrypt-only and decrypt-only encryptor instances per role.
- Log key presence (not contents) during configuration validation.
When it happens
Trigger: Creating RsaRawEncryptor with only a public key (or via a constructor that leaves privateKey unset) and then calling decrypt on ciphertext.
Common situations: Service configured for encryption-only (has the peer's public key) but code path attempts to decrypt incoming payloads; wiring errors where the keystore entry or PEM private key failed to load and null was passed silently.
Related errors
- Cannot decrypt
- Encryptor is not configured for decryption
- Cannot encrypt
- Cannot decrypt
- Cannot apply {configurer} to already built object
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/e2c3f9986c516062.
Report an issue: GitHub.