MyCATApache/Mycat-Server · error · IllegalArgumentException
Failed to get public key
Error message
Failed to get public key
What it means
DecryptUtil.getPublicKey() decodes a Base64 X.509-encoded RSA public key and asks the JCE KeyFactory to reconstruct it. If Base64 decoding or KeyFactory.generatePublic() fails for any reason, it rethrows as IllegalArgumentException('Failed to get public key') with the original cause attached.
Solutions
- Convert the key to X.509 SubjectPublicKeyInfo format: openssl rsa -pubin -in key.pub -pubout -outform DER | base64
- Confirm the input is the public key (not private) and contains only valid Base64 characters with no headers/newlines
- Inspect the wrapped cause (e.getCause()) — InvalidKeySpecException means wrong format, IOException/Base64 means corrupt input
- Regenerate a fresh RSA keypair with Mycat's tooling if the source of the key is unknown
Example fix
// before openssl rsa -in private.pem -pubout -out pub.pem // PKCS#1 or with PEM headers pasted directly // after openssl rsa -in private.pem -pubout -outform DER | base64 -w0 // then pass this Base64 string
Defensive patterns
Strategy: try-catch
Validate before calling
static boolean looksLikeX509Base64(String key){
if(key==null) return false;
String s = key.replaceAll("\\s","");
return s.length()%4==0 && s.matches("[A-Za-z0-9+/]+=*") && s.length() > 100;
} Try / catch
try { PublicKey pk = DecryptUtil.getPublicKey(b64); }
catch (IllegalArgumentException e) { throw new IllegalStateException("public key must be Base64 X.509 SubjectPublicKeyInfo; cause: " + e.getCause(), e); } Prevention
- Export public keys as X.509/SubjectPublicKeyInfo (openssl -pubout), not PKCS#1
- Strip PEM headers/footers and newlines before passing the Base64 body
- Log e.getCause() to distinguish InvalidKeySpecException from Base64 corruption
- Round-trip test: encode-then-decode the key once at startup
When it happens
Trigger: Passing a string that is not valid Base64 or not an X.509 SubjectPublicKeyInfo blob to getPublicKey(String); supplying an RSA public key exported in a different format (e.g. PKCS#1 'BEGIN RSA PUBLIC KEY' or OpenSSH format).
Common situations: Generating a keypair with openssl and pasting the public key directly without converting to X.509/SubjectPublicKeyInfo; whitespace or newlines corrupting the Base64; attempting to decrypt with a public key that was actually the private key field.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- host ,user passwrod need to decrype ,but decrype password…
- Illegal character
- String length must be a multiple of four.
- A batchSize of: with batchStatsAt of: will overrun the…
- Array has wrong size:
AI-assisted analysis of MyCATApache/Mycat-Server@65f8d8beb7 (2026-09-11).
Data as JSON: /api/errors/351cf79d7676c51b.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/io/mycat/util/DecryptUtil.java:142
PublicKey publicKey = getPublicKey(publicKeyText);
return decrypt(publicKey, cipherText);
}
public static PublicKey getPublicKey(String publicKeyText) {
if (publicKeyText == null || publicKeyText.length() == 0) {
publicKeyText = DecryptUtil.DEFAULT_PUBLIC_KEY_STRING;
}
try {
byte[] publicKeyBytes = Base64.base64ToByteArray(publicKeyText);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(
publicKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(x509KeySpec);
} catch (Exception e) {
throw new IllegalArgumentException("Failed to get public key", e);
}
}
public static String decrypt(PublicKey publicKey, String cipherText)
throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
try {
cipher.init(Cipher.DECRYPT_MODE, publicKey);
} catch (InvalidKeyException e) {
// 因为 IBM JDK 不支持私钥加密, 公钥解密, 所以要反转公私钥
// 也就是说对于解密, 可以通过公钥的参数伪造一个私钥对象欺骗 IBM JDK
RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
RSAPrivateKeySpec spec = new RSAPrivateKeySpec(rsaPublicKey.getModulus(), rsaPublicKey.getPublicExponent());
Key fakePrivateKey = KeyFactory.getInstance("RSA").generatePrivate(spec);
cipher = Cipher.getInstance("RSA"); //It is a stateful object. so we need to get new one.
cipher.init(Cipher.DECRYPT_MODE, fakePrivateKey);
}View on GitHub (pinned to 65f8d8beb7)