{"record":{"id":"6cc7da162ff5fba5","repo":"binarywang/WxJava","slug":"rsa-key-apisignaturersaprivatekey-pkc","errorCode":null,"errorMessage":"解析RSA KEY失败，请检查ApiSignatureRsaPrivateKey是否正确，需要PKCS8格式私钥","messagePattern":"解析RSA KEY失败，请检查ApiSignatureRsaPrivateKey是否正确，需要PKCS8格式私钥","errorType":"exception","errorClass":"SecurityException","httpStatus":null,"severity":"error","filePath":"weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java","lineNumber":1008,"sourceCode":"      reqData.addProperty(\"data\", base64Encode(encryptedData));\n      reqData.addProperty(\"authtag\", base64Encode(authTag));\n      String requestJson = reqData.toString();\n\n      // 计算签名 RSA，待签名串格式：urlpath\\nappid\\ntimestamp\\npostdata\n      String payload = buildSignaturePayload(urlPath, appId, timestamp, requestJson);\n      byte[] dataBuffer = payload.getBytes(StandardCharsets.UTF_8);\n      RSAPrivateKey priKey;\n      try {\n        String rsaPrivateKey = this.getWxMaConfig().getApiSignatureRsaPrivateKey();\n        rsaPrivateKey = rsaPrivateKey.replace(\"-----BEGIN PRIVATE KEY-----\", \"\");\n        rsaPrivateKey = rsaPrivateKey.replace(\"-----END PRIVATE KEY-----\", \"\");\n        rsaPrivateKey = rsaPrivateKey.replaceAll(\"\\\\s+\", \"\");\n        byte[] decoded = Base64.getDecoder().decode(rsaPrivateKey.getBytes(StandardCharsets.UTF_8));\n        PKCS8EncodedKeySpec rsaKeySpec = new PKCS8EncodedKeySpec(decoded);\n        priKey = (RSAPrivateKey) KeyFactory.getInstance(\"RSA\").generatePrivate(rsaKeySpec);\n      } catch (Exception ex) {\n        log.error(\"解析RSA KEY失败 {}\", aesKey, ex);\n        throw new SecurityException(\"解析RSA KEY失败，请检查ApiSignatureRsaPrivateKey是否正确，需要PKCS8格式私钥\", ex);\n      }\n      Signature signature = Signature.getInstance(\"RSASSA-PSS\");\n      // salt长度，需与SHA256结果长度(32)一致\n      PSSParameterSpec pssParameterSpec =\n          new PSSParameterSpec(\"SHA-256\", \"MGF1\", MGF1ParameterSpec.SHA256, 32, 1);\n      signature.setParameter(pssParameterSpec);\n      signature.initSign(priKey);\n      signature.update(dataBuffer);\n      byte[] sigBuffer = signature.sign();\n      String signatureString = base64Encode(sigBuffer);\n\n      Map<String, String> header = new HashMap<>();\n      header.put(\"Wechatmp-Signature\", signatureString);\n      header.put(\"Wechatmp-Appid\", appId);\n      header.put(\"Wechatmp-TimeStamp\", String.valueOf(timestamp));\n      header.put(\"Wechatmp-Serial\", rsaKeySn);\n      log.debug(\"发送请求uri:{}, headers:{}, postData:{}\", url, header, requestJson);\n      WxMaApiResponse response =","sourceCodeStart":990,"sourceCodeEnd":1026,"githubUrl":"https://github.com/binarywang/WxJava/blob/1c43293a3c2c9d7e91304b6d037fb017f680d0c6/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java#L990-L1026","documentation":"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.","triggerScenarios":"Calling postWithSignature() when apiSignatureRsaPrivateKey is in PKCS1/OpenSSL format instead of PKCS8, or is malformed/truncated.","commonSituations":"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.","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"],"exampleFix":"# Convert PKCS1 to PKCS8\nopenssl pkcs8 -topk8 -nocrypt -in original_key.pem -out pkcs8_key.pem\n\n// Then set in config\nwxMaConfig.setApiSignatureRsaPrivateKey(pkcs8KeyContent);","handlingStrategy":"validation","validationCode":"// Validate RSA key parses correctly before calling postWithSignature\nString rsaKey = wxMaConfig.getApiSignatureRsaPrivateKey();\ntry {\n  String cleaned = rsaKey\n      .replace(\"-----BEGIN PRIVATE KEY-----\", \"\")\n      .replace(\"-----END PRIVATE KEY-----\", \"\")\n      .replaceAll(\"\\\\s+\", \"\");\n  byte[] decoded = Base64.getDecoder().decode(cleaned);\n  KeyFactory.getInstance(\"RSA\").generatePrivate(new PKCS8EncodedKeySpec(decoded));\n} catch (Exception e) {\n  throw new IllegalStateException(\"ApiSignatureRsaPrivateKey is not valid PKCS8\", e);\n}\nservice.postWithSignature(url, jsonObject);","typeGuard":"private static boolean isValidPkcs8RsaKey(String pemKey) {\n  if (pemKey == null || pemKey.isEmpty()) return false;\n  try {\n    String cleaned = pemKey.replace(\"-----BEGIN PRIVATE KEY-----\", \"\")\n        .replace(\"-----END PRIVATE KEY-----\", \"\").replaceAll(\"\\\\s+\", \"\");\n    byte[] decoded = Base64.getDecoder().decode(cleaned);\n    KeyFactory.getInstance(\"RSA\").generatePrivate(new PKCS8EncodedKeySpec(decoded));\n    return true;\n  } catch (Exception e) {\n    return false;\n  }\n}","tryCatchPattern":"try {\n  service.postWithSignature(url, jsonObject);\n} catch (SecurityException e) {\n  if (e.getMessage().contains(\"RSA KEY\")) {\n    log.error(\"Invalid RSA private key — ensure it is PKCS8 format\");\n    // convert key and retry, or fall back\n  } else {\n    throw e;\n  }\n}","preventionTips":["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)"],"tags":["configuration","miniapp","security","crypto","api-signature","pkcs8"],"backgroundTag":null,"analyzedSha":"1c43293a3c2c9d7e91304b6d037fb017f680d0c6","analyzedAt":"2026-08-14T02:29:11.060Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}