binarywang/WxJava · error · SecurityException
解析RSA KEY失败,请检查ApiSignatureRsaPrivateKey是否正确,需要PKCS8格式私钥
Error message
解析RSA KEY失败,请检查ApiSignatureRsaPrivateKey是否正确,需要PKCS8格式私钥
What it means
Thrown as SecurityException when RSA private key parsing fails in postWithSignature(). The code strips PEM headers and whitespace, Base64-decodes the key, and wraps it in PKCS8EncodedKeySpec. A failure means the key is not in valid PKCS8 DER format. Note: the log statement at line 1008 logs aesKey instead of rsaPrivateKey — a minor diagnostic bug that does not affect the error itself.
Source
Thrown at weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java:1008
reqData.addProperty("data", base64Encode(encryptedData));
reqData.addProperty("authtag", base64Encode(authTag));
String requestJson = reqData.toString();
// 计算签名 RSA,待签名串格式:urlpath\nappid\ntimestamp\npostdata
String payload = buildSignaturePayload(urlPath, appId, timestamp, requestJson);
byte[] dataBuffer = payload.getBytes(StandardCharsets.UTF_8);
RSAPrivateKey priKey;
try {
String rsaPrivateKey = this.getWxMaConfig().getApiSignatureRsaPrivateKey();
rsaPrivateKey = rsaPrivateKey.replace("-----BEGIN PRIVATE KEY-----", "");
rsaPrivateKey = rsaPrivateKey.replace("-----END PRIVATE KEY-----", "");
rsaPrivateKey = rsaPrivateKey.replaceAll("\\s+", "");
byte[] decoded = Base64.getDecoder().decode(rsaPrivateKey.getBytes(StandardCharsets.UTF_8));
PKCS8EncodedKeySpec rsaKeySpec = new PKCS8EncodedKeySpec(decoded);
priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(rsaKeySpec);
} catch (Exception ex) {
log.error("解析RSA KEY失败 {}", aesKey, ex);
throw new SecurityException("解析RSA KEY失败,请检查ApiSignatureRsaPrivateKey是否正确,需要PKCS8格式私钥", ex);
}
Signature signature = Signature.getInstance("RSASSA-PSS");
// salt长度,需与SHA256结果长度(32)一致
PSSParameterSpec pssParameterSpec =
new PSSParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, 32, 1);
signature.setParameter(pssParameterSpec);
signature.initSign(priKey);
signature.update(dataBuffer);
byte[] sigBuffer = signature.sign();
String signatureString = base64Encode(sigBuffer);
Map<String, String> header = new HashMap<>();
header.put("Wechatmp-Signature", signatureString);
header.put("Wechatmp-Appid", appId);
header.put("Wechatmp-TimeStamp", String.valueOf(timestamp));
header.put("Wechatmp-Serial", rsaKeySn);
log.debug("发送请求uri:{}, headers:{}, postData:{}", url, header, requestJson);
WxMaApiResponse response =View on GitHub (pinned to 1c43293a3c)
Solutions
- Convert your key to PKCS8 format: openssl pkcs8 -topk8 -nocrypt -in pkcs1.key -out pkcs8.key
- Ensure the key uses '-----BEGIN PRIVATE KEY-----' / '-----END PRIVATE KEY-----' PEM markers (the code strips these)
- Verify the key is not truncated or corrupted — compare the decoded byte length and structure
Example fix
# Convert PKCS1 to PKCS8 openssl pkcs8 -topk8 -nocrypt -in original_key.pem -out pkcs8_key.pem // Then set in config wxMaConfig.setApiSignatureRsaPrivateKey(pkcs8KeyContent);
Defensive patterns
Strategy: validation
Validate before calling
// Validate RSA key parses correctly before calling postWithSignature
String rsaKey = wxMaConfig.getApiSignatureRsaPrivateKey();
try {
String cleaned = rsaKey
.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");
byte[] decoded = Base64.getDecoder().decode(cleaned);
KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
} catch (Exception e) {
throw new IllegalStateException("ApiSignatureRsaPrivateKey is not valid PKCS8", e);
}
service.postWithSignature(url, jsonObject); Type guard
private static boolean isValidPkcs8RsaKey(String pemKey) {
if (pemKey == null || pemKey.isEmpty()) return false;
try {
String cleaned = pemKey.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "").replaceAll("\\s+", "");
byte[] decoded = Base64.getDecoder().decode(cleaned);
KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
return true;
} catch (Exception e) {
return false;
}
} Try / catch
try {
service.postWithSignature(url, jsonObject);
} catch (SecurityException e) {
if (e.getMessage().contains("RSA KEY")) {
log.error("Invalid RSA private key — ensure it is PKCS8 format");
// convert key and retry, or fall back
} else {
throw e;
}
} Prevention
- Generate keys in PKCS8 format: openssl genpkey -algorithm RSA -out key.pem -pkeyopt rsa_keygen_bits:2048
- Or convert: openssl pkcs8 -topk8 -nocrypt -in pkcs1.key -out pkcs8.key
- Verify key format at application startup with a parse test
- Ensure PEM markers are '-----BEGIN PRIVATE KEY-----' (PKCS8), not '-----BEGIN RSA PRIVATE KEY-----' (PKCS1)
When it happens
Trigger: Calling postWithSignature() when apiSignatureRsaPrivateKey is in PKCS1/OpenSSL format instead of PKCS8, or is malformed/truncated.
Common situations: Key generated in PKCS1 format (openssl genrsa default) instead of PKCS8; wrong PEM header ('-----BEGIN RSA PRIVATE KEY-----' instead of '-----BEGIN PRIVATE KEY-----'); key truncated during file copy or environment variable injection.
Related errors
- 解析AES KEY失败,请检查ApiSignatureAesKey是否正确
- ApiSignatureRsaPrivateKeySn不能为空,请检查配置
- 响应的appId不符
- 请配置会话存档解密方式
- uri参数中不允许有access_token:
AI-assisted analysis of binarywang/WxJava@1c43293a3c (2026-08-14).
Data as JSON: /api/errors/6cc7da162ff5fba5.
Report an issue: GitHub.