• 微信支付V3获取平台证书并解密平台证书详细流程


    公司要搞服务号商户卷功能,所以用到了创建商户号接口,有很多数据需要平台证书单独加密,并且图片上传接口返回数据也需要平台证书验签。

       就搞了一下,现在说一下具体细节:

         1:直接点进 敏感信息加密说明

     2 看到微信说加密需要 平台证书

     这里你要搞清楚:商户号证书  和  平台证书不是一个东西,

     商户号证书:是服务商下载的证书

    平台证书:微信支付证书

    3:现在就去下载微信平台证书,请求接口方式下载

     

     不废话了,直接上获取平台证书代码

       

    1. //获取 获取平台证书列表 测试成功
    2. public static void main(String[] args) throws Exception {
    3. //时间戳
    4. long timestamp = System.currentTimeMillis() / 1000;
    5. //随机字符串(用UUID去掉-就行)
    6. String nonce = IdUtil.fastSimpleUUID().toUpperCase();
    7. String body = "";
    8. //拼接要签名的字符串
    9. PrivateKey privateKey = PayKit.getPrivateKey("这里填商户平台私钥证书");
    10. //拼接要签名的字符串
    11. String orgSignText = "GET\n"
    12. + "/v3/certificates\n"
    13. + timestamp + "\n"
    14. + nonce + "\n"
    15. + body + "\n";
    16. // 生成签名
    17. String sign = RsaKit.encryptByPrivateKey(orgSignText, privateKey);
    18. //要放在HttpHeader中的auth信息
    19. // 获取商户证书序列号 这里填写公钥路径 也就是apiclient_cert.pem这个文件的路径
    20. //证书序列号
    21. X509Certificate certificate = PayKit.getCertificate(FileUtil.getInputStream("填你的apiclient_cert.pem"));
    22. String serialNo = certificate.getSerialNumber().toString(16).toUpperCase();
    23. String auth = "WECHATPAY2-SHA256-RSA2048 "
    24. + "mchid=\"商户号\",nonce_str=\""
    25. + nonce + "\",timestamp=\"" + timestamp
    26. + "\",serial_no=\"" + serialNo + "\",signature=\"" + sign + "\"";
    27. String url = "https://api.mch.weixin.qq.com/v3/certificates";
    28. HashMap<String, Object> tmap = new HashMap<String, Object>();
    29. tmap.put("Authorization",auth);//tmap.put("token","tonken值");
    30. tmap.put("Accept","application/json");
    31. tmap.put("User-Agent","https://zh.wikipedia.org/wiki/User_agent");
    32. String vmsg= httpGet(url,tmap);//获取请求的返回结果
    33. String rs = HttpClientUtil.sendGetRequest(url, null);
    34. System.out.println("获取平台证书"+vmsg);
    35. }

    下面是具体用到的工具类:

    1. public class RsaKit {
    2. /**
    3. * 加密算法RSA
    4. */
    5. private static final String KEY_ALGORITHM = "RSA";
    6. /**
    7. * 私钥签名
    8. *
    9. * @param data 需要加密的数据
    10. * @param privateKey 私钥
    11. * @return 加密后的数据
    12. * @throws Exception 异常信息
    13. */
    14. public static String encryptByPrivateKey(String data, PrivateKey privateKey) throws Exception {
    15. java.security.Signature signature = java.security.Signature.getInstance("SHA256WithRSA");
    16. signature.initSign(privateKey);
    17. signature.update(data.getBytes(StandardCharsets.UTF_8));
    18. byte[] signed = signature.sign();
    19. return StrUtil.str(Base64.encode(signed));
    20. }
    21. /**
    22. * 从字符串中加载私钥
    23. * 加载时使用的是PKCS8EncodedKeySpec(PKCS#8编码的Key指令)。
    24. *
    25. * @param privateKeyStr 私钥
    26. * @return {@link PrivateKey}
    27. * @throws Exception 异常信息
    28. */
    29. public static PrivateKey loadPrivateKey(String privateKeyStr) throws Exception {
    30. try {
    31. byte[] buffer = Base64.decode(privateKeyStr);
    32. PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
    33. KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
    34. return keyFactory.generatePrivate(keySpec);
    35. } catch (NoSuchAlgorithmException e) {
    36. throw new Exception("无此算法");
    37. } catch (InvalidKeySpecException e) {
    38. throw new Exception("私钥非法");
    39. } catch (NullPointerException e) {
    40. throw new Exception("私钥数据为空");
    41. }
    42. }
    43. /**
    44. * 公钥验证签名
    45. *
    46. * @param data 需要加密的数据
    47. * @param sign 签名
    48. * @param publicKey 公钥
    49. * @return 验证结果
    50. * @throws Exception 异常信息
    51. */
    52. public static boolean checkByPublicKey(String data, String sign, PublicKey publicKey) throws Exception {
    53. java.security.Signature signature = java.security.Signature.getInstance("SHA256WithRSA");
    54. signature.initVerify(publicKey);
    55. signature.update(data.getBytes(StandardCharsets.UTF_8));
    56. return signature.verify(Base64.decode(sign.getBytes(StandardCharsets.UTF_8)));
    57. }
    58. }
    1. public class PayKit {
    2. /**
    3. * 获取证书
    4. *
    5. * @param inputStream 证书文件
    6. * @return {@link X509Certificate} 获取证书
    7. */
    8. public static X509Certificate getCertificate(InputStream inputStream) {
    9. try {
    10. CertificateFactory cf = CertificateFactory.getInstance("X509");
    11. X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);
    12. cert.checkValidity();
    13. return cert;
    14. } catch (CertificateExpiredException e) {
    15. throw new RuntimeException("证书已过期", e);
    16. } catch (CertificateNotYetValidException e) {
    17. throw new RuntimeException("证书尚未生效", e);
    18. } catch (CertificateException e) {
    19. throw new RuntimeException("无效的证书", e);
    20. }
    21. }
    22. /**
    23. * 简化的UUID,去掉了横线,使用性能更好的 ThreadLocalRandom 生成UUID
    24. *
    25. * @return 简化的 UUID,去掉了横线
    26. */
    27. public static String generateStr() {
    28. return IdUtil.fastSimpleUUID();
    29. }
    30. /**
    31. * 构造签名串
    32. *
    33. * @param method {@link RequestMethod} GET,POST,PUT等
    34. * @param url 请求接口 /v3/certificates
    35. * @param timestamp 获取发起请求时的系统当前时间戳
    36. * @param nonceStr 随机字符串
    37. * @param body 请求报文主体
    38. * @return 待签名字符串
    39. */
    40. public static String buildSignMessage(String method, String url, String timestamp, String nonceStr, String body) {
    41. ArrayList arrayList = new ArrayList<>();
    42. arrayList.add(method);
    43. arrayList.add(url);
    44. arrayList.add(String.valueOf(timestamp));
    45. arrayList.add(nonceStr);
    46. arrayList.add(body);
    47. return buildSignMessage(arrayList);
    48. }
    49. /**
    50. * 构造签名串
    51. *
    52. * @param signMessage 待签名的参数
    53. * @return 构造后带待签名串
    54. */
    55. public static String buildSignMessage(ArrayList signMessage) {
    56. if (signMessage == null || signMessage.size() <= 0) {
    57. return null;
    58. }
    59. StringBuilder sbf = new StringBuilder();
    60. for (String str : signMessage) {
    61. sbf.append(str).append("\n");
    62. }
    63. System.out.println("待签名字符串内容:" + sbf.toString());
    64. System.out.println("待签名字符串长度:" + sbf.toString().length());
    65. return sbf.toString();
    66. }
    67. /**
    68. * v3 接口创建签名
    69. *
    70. * @param signMessage 待签名的参数
    71. * @param keyPath key.pem 证书路径
    72. * @return 生成 v3 签名
    73. * @throws Exception 异常信息
    74. */
    75. public static String createSign(String signMessage, String keyPath) throws Exception {
    76. if (StrUtil.isEmpty(signMessage)) {
    77. return null;
    78. }
    79. // 获取商户私钥
    80. PrivateKey privateKey = PayKit.getPrivateKey(keyPath);
    81. // 生成签名
    82. return RsaKit.encryptByPrivateKey(signMessage, privateKey);
    83. }
    84. /**
    85. * 获取商户私钥
    86. *
    87. * @param keyPath 商户私钥证书路径
    88. * @return {@link PrivateKey} 商户私钥
    89. * @throws Exception 异常信息
    90. */
    91. public static PrivateKey getPrivateKey(String keyPath) throws Exception {
    92. String originalKey = FileUtil.readUtf8String(keyPath);
    93. String privateKey = originalKey
    94. .replace("-----BEGIN PRIVATE KEY-----", "")
    95. .replace("-----END PRIVATE KEY-----", "")
    96. .replaceAll("\\s+", "");
    97. return RsaKit.loadPrivateKey(privateKey);
    98. }
    99. /**
    100. * 获取授权认证信息
    101. *
    102. * @param mchId 商户号
    103. * @param serialNo 商户API证书序列号
    104. * @param nonceStr 请求随机串
    105. * @param timestamp 时间戳
    106. * @param signature 签名值
    107. * @param authType 认证类型,目前为WECHATPAY2-SHA256-RSA2048
    108. * @return 请求头 Authorization
    109. */
    110. public static String getAuthorization(String mchId, String serialNo, String nonceStr, String timestamp, String signature, String authType) {
    111. Map params = new HashMap<>(5);
    112. params.put("mchid", mchId);
    113. params.put("serial_no", serialNo);
    114. params.put("nonce_str", nonceStr);
    115. params.put("timestamp", timestamp);
    116. params.put("signature", signature);
    117. return authType.concat(" ").concat(createLinkString(params, ",", false, true));
    118. }
    119. /**
    120. * @param params 需要排序并参与字符拼接的参数组
    121. * @param encode 是否进行URLEncoder
    122. * @return 拼接后字符串
    123. */
    124. public static String createLinkString(Map params, boolean encode) {
    125. return createLinkString(params, "&", encode);
    126. }
    127. /**
    128. * @param params 需要排序并参与字符拼接的参数组
    129. * @param connStr 连接符号
    130. * @param encode 是否进行URLEncoder
    131. * @return 拼接后字符串
    132. */
    133. public static String createLinkString(Map params, String connStr, boolean encode) {
    134. return createLinkString(params, connStr, encode, false);
    135. }
    136. public static String createLinkString(Map params, String connStr, boolean encode, boolean quotes) {
    137. List keys = new ArrayList<>(params.keySet());
    138. Collections.sort(keys);
    139. StringBuilder content = new StringBuilder();
    140. for (int i = 0; i < keys.size(); i++) {
    141. String key = keys.get(i);
    142. String value = params.get(key);
    143. // 拼接时,不包括最后一个&字符
    144. if (i == keys.size() - 1) {
    145. if (quotes) {
    146. content.append(key).append("=").append('"').append(encode ? urlEncode(value) : value).append('"');
    147. } else {
    148. content.append(key).append("=").append(encode ? urlEncode(value) : value);
    149. }
    150. } else {
    151. if (quotes) {
    152. content.append(key).append("=").append('"').append(encode ? urlEncode(value) : value).append('"').append(connStr);
    153. } else {
    154. content.append(key).append("=").append(encode ? urlEncode(value) : value).append(connStr);
    155. }
    156. }
    157. }
    158. return content.toString();
    159. }
    160. /**
    161. * URL 编码
    162. *
    163. * @param src 需要编码的字符串
    164. * @return 编码后的字符串
    165. */
    166. public static String urlEncode(String src) {
    167. try {
    168. return URLEncoder.encode(src, CharsetUtil.UTF_8).replace("+", "%20");
    169. } catch (UnsupportedEncodingException e) {
    170. e.printStackTrace();
    171. return null;
    172. }
    173. }
    174. /**
    175. * 构造签名串
    176. *
    177. * @param timestamp 应答时间戳
    178. * @param nonceStr 应答随机串
    179. * @param body 应答报文主体
    180. * @return 应答待签名字符串
    181. */
    182. public static String buildSignMessage(String timestamp, String nonceStr, String body) {
    183. ArrayList arrayList = new ArrayList<>();
    184. arrayList.add(timestamp);
    185. arrayList.add(nonceStr);
    186. arrayList.add(body);
    187. return buildSignMessage(arrayList);
    188. }
    189. /**
    190. * 公钥加密
    191. *
    192. * @param data 待加密数据
    193. * @param certificate 平台公钥证书
    194. * @return 加密后的数据
    195. * @throws Exception 异常信息
    196. */
    197. public static String rsaEncryptOAEP(String data, X509Certificate certificate) throws Exception {
    198. try {
    199. Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
    200. cipher.init(Cipher.ENCRYPT_MODE, certificate.getPublicKey());
    201. byte[] dataByte = data.getBytes(StandardCharsets.UTF_8);
    202. byte[] cipherData = cipher.doFinal(dataByte);
    203. return Base64.encode(cipherData);
    204. } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
    205. throw new RuntimeException("当前Java环境不支持RSA v1.5/OAEP", e);
    206. } catch (InvalidKeyException e) {
    207. throw new IllegalArgumentException("无效的证书", e);
    208. } catch (IllegalBlockSizeException | BadPaddingException e) {
    209. throw new IllegalBlockSizeException("加密原串的长度不能超过214字节");
    210. }
    211. }
    212. /**
    213. * 私钥解密
    214. *
    215. * @param cipherText 加密字符
    216. * @param privateKey 私钥
    217. * @return 解密后的数据
    218. * @throws Exception 异常信息
    219. */
    220. public static String rsaDecryptOAEP(String cipherText, PrivateKey privateKey) throws Exception {
    221. try {
    222. Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
    223. cipher.init(Cipher.DECRYPT_MODE, privateKey);
    224. byte[] data = Base64.decode(cipherText);
    225. return new String(cipher.doFinal(data), StandardCharsets.UTF_8);
    226. } catch (NoSuchPaddingException | NoSuchAlgorithmException e) {
    227. throw new RuntimeException("当前Java环境不支持RSA v1.5/OAEP", e);
    228. } catch (InvalidKeyException e) {
    229. throw new IllegalArgumentException("无效的私钥", e);
    230. } catch (BadPaddingException | IllegalBlockSizeException e) {
    231. throw new BadPaddingException("解密失败");
    232. }
    233. }
    234. }
    1. public class HttpClientUtil
    2. {
    3. public static final String SunX509 = "SunX509";
    4. public static final String JKS = "JKS";
    5. public static final String PKCS12 = "PKCS12";
    6. public static final String TLS = "TLS";
    7. public static HttpURLConnection getHttpURLConnection(String strUrl)
    8. throws IOException
    9. {
    10. URL url = new URL(strUrl);
    11. HttpURLConnection httpURLConnection = (HttpURLConnection)url
    12. .openConnection();
    13. return httpURLConnection;
    14. }
    15. /**
    16. * 发送HTTP_GET请求
    17. *
    18. * @see 该方法会自动关闭连接,释放资源
    19. * @param reqURL
    20. * 请求地址(含参数)
    21. * @param decodeCharset
    22. * 解码字符集,解析响应数据时用之,其为null时默认采用UTF-8解码
    23. * @return 远程主机响应正文
    24. */
    25. public static String sendGetRequest(String reqURL, String decodeCharset) {
    26. long responseLength = 0; // 响应长度
    27. String responseContent = null; // 响应内容
    28. HttpClient httpClient = new DefaultHttpClient(); // 创建默认的httpClient实例
    29. HttpGet httpGet = new HttpGet(reqURL); // 创建org.apache.http.client.methods.HttpGet
    30. try {
    31. HttpResponse response = httpClient.execute(httpGet); // 执行GET请求
    32. HttpEntity entity = response.getEntity(); // 获取响应实体
    33. if (null != entity) {
    34. responseLength = entity.getContentLength();
    35. responseContent = EntityUtils.toString(entity, decodeCharset == null ? "UTF-8" : decodeCharset);
    36. EntityUtils.consume(entity); // Consume response content
    37. }
    38. System.out.println("请求地址: " + httpGet.getURI());
    39. System.out.println("响应状态: " + response.getStatusLine());
    40. System.out.println("响应长度: " + responseLength);
    41. System.out.println("响应内容: " + responseContent);
    42. } catch (ClientProtocolException e) {
    43. System.out.println("该异常通常是协议错误导致,比如构造HttpGet对象时传入的协议不对(将'http'写成'htp')或者服务器端返回的内容不符合HTTP协议要求等,堆栈信息如下");
    44. } catch (ParseException e) {
    45. System.out.println(e.getMessage());
    46. } catch (IOException e) {
    47. System.out.println("该异常通常是网络原因引起的,如HTTP服务器未启动等,堆栈信息如下");
    48. } finally {
    49. httpClient.getConnectionManager().shutdown(); // 关闭连接,释放资源
    50. }
    51. return responseContent;
    52. }
    53. /**
    54. * 发送HTTP_POST请求
    55. *
    56. * @see 该方法为
    57. * sendPostRequest(String,String,boolean,String,String)
    58. * 的简化方法
    59. * @see 该方法在对请求数据的编码和响应数据的解码时,所采用的字符集均为UTF-8
    60. * @seeisEncoder=true时,其会自动对sendData中的[中文][|][
    61. * ]等特殊字符进行URLEncoder.encode(string,"UTF-8")
    62. * @param isEncoder
    63. * 用于指明请求数据是否需要UTF-8编码,true为需要
    64. */
    65. public static String sendPostRequest(String reqURL, String sendData, boolean isEncoder) {
    66. return sendPostRequest(reqURL, sendData, isEncoder, null, null,"application/json");
    67. }
    68. /**
    69. * 发送HTTP_POST请求
    70. *
    71. * @see 该方法会自动关闭连接,释放资源
    72. * @seeisEncoder=true时,其会自动对sendData中的[中文][|][
    73. * ]等特殊字符进行URLEncoder.encode(string,encodeCharset)
    74. * @param reqURL
    75. * 请求地址
    76. * @param sendData
    77. * 请求参数,若有多个参数则应拼接成param11=value11¶m22=value22¶m33=value33的形式后,
    78. * 传入该参数中
    79. * @param isEncoder
    80. * 请求数据是否需要encodeCharset编码,true为需要
    81. * @param encodeCharset
    82. * 编码字符集,编码请求数据时用之,其为null时默认采用UTF-8解码
    83. * @param decodeCharset
    84. * 解码字符集,解析响应数据时用之,其为null时默认采用UTF-8解码
    85. * @return 远程主机响应正文
    86. */
    87. public static String sendPostRequest(String reqURL, String sendData, boolean isEncoder, String encodeCharset,
    88. String decodeCharset,String contentType) {
    89. String responseContent = null;
    90. HttpClient httpClient = new DefaultHttpClient();
    91. HttpPost httpPost = new HttpPost(reqURL);
    92. // httpPost.setHeader(HTTP.CONTENT_TYPE,
    93. // "application/x-www-form-urlencoded; charset=UTF-8");
    94. httpPost.setHeader(HTTP.CONTENT_TYPE, contentType);
    95. try {
    96. if (isEncoder) {
    97. httpPost.setEntity(new StringEntity(sendData, encodeCharset == null ? "UTF-8" : encodeCharset));
    98. } else {
    99. httpPost.setEntity(new StringEntity(sendData));
    100. }
    101. // 设置请求超时时间
    102. httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 5000);
    103. HttpResponse response = httpClient.execute(httpPost);
    104. HttpEntity entity = response.getEntity();
    105. if (null != entity) {
    106. responseContent = EntityUtils.toString(entity, decodeCharset == null ? "UTF-8" : decodeCharset);
    107. EntityUtils.consume(entity);
    108. }
    109. } catch (Exception e) {
    110. System.out.println("与[" + reqURL + "]通信过程中发生异常,堆栈信息如下");
    111. e.printStackTrace();
    112. } finally {
    113. httpClient.getConnectionManager().shutdown();
    114. }
    115. return responseContent;
    116. }
    117. public static HttpsURLConnection getHttpsURLConnection(String strUrl)
    118. throws IOException
    119. {
    120. URL url = new URL(strUrl);
    121. HttpsURLConnection httpsURLConnection = (HttpsURLConnection)url
    122. .openConnection();
    123. return httpsURLConnection;
    124. }
    125. public static String getURL(String strUrl)
    126. {
    127. if (strUrl != null) {
    128. int indexOf = strUrl.indexOf("?");
    129. if (-1 != indexOf) {
    130. return strUrl.substring(0, indexOf);
    131. }
    132. return strUrl;
    133. }
    134. return strUrl;
    135. }
    136. public static String getQueryString(String strUrl)
    137. {
    138. if (strUrl != null) {
    139. int indexOf = strUrl.indexOf("?");
    140. if (-1 != indexOf) {
    141. return strUrl.substring(indexOf + 1, strUrl.length());
    142. }
    143. return "";
    144. }
    145. return strUrl;
    146. }
    147. public static Map queryString2Map(String queryString)
    148. {
    149. if ((queryString == null) || ("".equals(queryString))) {
    150. return null;
    151. }
    152. Map m = new HashMap();
    153. String[] strArray = queryString.split("&");
    154. for (int index = 0; index < strArray.length; index++) {
    155. String pair = strArray[index];
    156. putMapByPair(pair, m);
    157. }
    158. return m;
    159. }
    160. public static void putMapByPair(String pair, Map m)
    161. {
    162. if ((pair == null) || ("".equals(pair))) {
    163. return;
    164. }
    165. int indexOf = pair.indexOf("=");
    166. if (-1 != indexOf) {
    167. String k = pair.substring(0, indexOf);
    168. String v = pair.substring(indexOf + 1, pair.length());
    169. if ((k != null) && (!"".equals(k))) {
    170. m.put(k, v);
    171. }
    172. } else {
    173. m.put(pair, "");
    174. }
    175. }
    176. public static String bufferedReader2String(BufferedReader reader)
    177. throws IOException
    178. {
    179. StringBuffer buf = new StringBuffer();
    180. String line = null;
    181. while ((line = reader.readLine()) != null) {
    182. buf.append(line);
    183. buf.append("\r\n");
    184. }
    185. return buf.toString();
    186. }
    187. public static void doOutput(OutputStream out, byte[] data, int len)
    188. throws IOException
    189. {
    190. int dataLen = data.length;
    191. int off = 0;
    192. while (off < dataLen) {
    193. if (len >= dataLen) {
    194. out.write(data, off, dataLen);
    195. } else {
    196. out.write(data, off, len);
    197. }
    198. out.flush();
    199. off += len;
    200. dataLen -= len;
    201. }
    202. }
    203. public static SSLContext getSSLContext(FileInputStream trustFileInputStream, String trustPasswd, FileInputStream keyFileInputStream, String keyPasswd)
    204. throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException, UnrecoverableKeyException, KeyManagementException
    205. {
    206. TrustManagerFactory tmf =
    207. TrustManagerFactory.getInstance("SunX509");
    208. KeyStore trustKeyStore = KeyStore.getInstance("JKS");
    209. trustKeyStore.load(trustFileInputStream,
    210. str2CharArray(trustPasswd));
    211. tmf.init(trustKeyStore);
    212. char[] kp = str2CharArray(keyPasswd);
    213. KeyManagerFactory kmf =
    214. KeyManagerFactory.getInstance("SunX509");
    215. KeyStore ks = KeyStore.getInstance("PKCS12");
    216. ks.load(keyFileInputStream, kp);
    217. kmf.init(ks, kp);
    218. SecureRandom rand = new SecureRandom();
    219. SSLContext ctx = SSLContext.getInstance("TLS");
    220. ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), rand);
    221. return ctx;
    222. }
    223. public static Certificate getCertificate(File cafile)
    224. throws CertificateException, IOException
    225. {
    226. CertificateFactory cf = CertificateFactory.getInstance("X.509");
    227. FileInputStream in = new FileInputStream(cafile);
    228. Certificate cert = cf.generateCertificate(in);
    229. in.close();
    230. return cert;
    231. }
    232. public static char[] str2CharArray(String str)
    233. {
    234. if (str == null) {
    235. return null;
    236. }
    237. return str.toCharArray();
    238. }
    239. public static void storeCACert(Certificate cert, String alias, String password, OutputStream out)
    240. throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException
    241. {
    242. KeyStore ks = KeyStore.getInstance("JKS");
    243. ks.load(null, null);
    244. ks.setCertificateEntry(alias, cert);
    245. ks.store(out, str2CharArray(password));
    246. }
    247. public static InputStream String2Inputstream(String str)
    248. {
    249. return new ByteArrayInputStream(str.getBytes());
    250. }
    251. }

    返回结果:

    这就获取到了微信平台证书,但是要注意,这只是获取到了平台证书加密密文 还要进行解密,直接用微信支付文档里面的解密代码就可以。

     

    然后解析出真正的微信证书。

    注意这里解密有个问题:解密出现Illegal key size错误

       解决:微信支付V3支付通知JAVA解密出现Illegal key size错误 | 微信开放社区

    可以用微信证书去加/解密指定内容:

     好了,结束,希望对你有所帮助!

  • 相关阅读:
    去哪里找JAVA项目练手?
    Python QGIS 3自动化教程
    ZJUBCA研报分享 | 《BTC/USDT周内效应研究》
    GoogLeNet
    chrome安装vue devtools
    鸿鹄工程项目管理系统em Spring Cloud+Spring Boot+前后端分离构建工程项目管理系统
    二分查找(c语言)
    FasterViT:英伟达提出分层注意力,构造高吞吐CNN-ViT混合网络 | ICLR 2024
    深入解析JVM G1 垃圾回收器
    智慧工地管理云平台源码,Spring Cloud +Vue+UniApp
  • 原文地址:https://blog.csdn.net/qq_37272886/article/details/126068981