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

  1. Convert your key to PKCS8 format: openssl pkcs8 -topk8 -nocrypt -in pkcs1.key -out pkcs8.key
  2. Ensure the key uses '-----BEGIN PRIVATE KEY-----' / '-----END PRIVATE KEY-----' PEM markers (the code strips these)
  3. 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

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


AI-assisted analysis of binarywang/WxJava@1c43293a3c (2026-08-14). Data as JSON: /api/errors/6cc7da162ff5fba5. Report an issue: GitHub.