package com.dsh.course.util.wx; import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.io.BufferedReader; import java.io.FileReader; import java.nio.charset.StandardCharsets; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.Security; import java.security.Signature; import java.security.spec.PKCS8EncodedKeySpec; import java.util.ArrayList; import java.util.Base64; import java.util.List; import java.util.Map; public class WeChatV3SignUtil { static { Security.addProvider(new BouncyCastleProvider()); } /** * 从 PEM 文件中读取私钥内容 */ public static PrivateKey loadPrivateKeyFromPem(String pemFilePath) throws Exception { StringBuilder sb = new StringBuilder(); try (BufferedReader reader = new BufferedReader(new FileReader(pemFilePath))) { String line; while ((line = reader.readLine()) != null) { if (!line.startsWith("-----") && !line.endsWith("-----")) { sb.append(line); } } } byte[] pkcs8Bytes = Base64.getDecoder().decode(sb.toString()); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pkcs8Bytes); KeyFactory kf = KeyFactory.getInstance("RSA", "BC"); return kf.generatePrivate(keySpec); } /** * 构造待签名字符串(按 key 字典序排序) */ public static String buildSignMessage(Map map) { List keys = new ArrayList<>(map.keySet()); // Collections.sort(keys); StringBuilder sb = new StringBuilder(); sb.append(map.get("appid")).append("\n"); sb.append(map.get("timestamp")).append("\n"); sb.append(map.get("noncestr")).append("\n"); sb.append(map.get("prepayid")).append("\n"); return sb.toString(); } /** * 使用商户私钥生成签名(SHA256withRSA + Base64) */ public static String signWithPrivateKey(String message, String privateKeyPath) throws Exception { PrivateKey privateKey = loadPrivateKeyFromPem(privateKeyPath); Signature signature = Signature.getInstance("SHA256withRSA"); signature.initSign(privateKey); signature.update(message.getBytes(StandardCharsets.UTF_8)); byte[] signedBytes = signature.sign(); return Base64.getEncoder().encodeToString(signedBytes); } }