Browse Source

优化医保移动支付加解密

lighter 10 months ago
parent
commit
3e7cc77376

+ 5 - 12
src/main/java/thyyxxk/wxservice_server/controller/WeChatRedirectController.java

@@ -60,22 +60,15 @@ public class WeChatRedirectController {
     }
 
     @PassToken
-    @GetMapping("/remotePageTest")
-    public void remotePageTest(@RequestParam("code") String code, HttpServletResponse response) {
+    @GetMapping("/selectAssessmentPatient")
+    public void selectAssessmentPatient(HttpServletResponse response) {
         try {
-            response.sendRedirect("http://staticweb.hnthyy.cn/wxService/" + code);
+            response.sendRedirect("https://open.weixin.qq.com/connect/oauth2/authorize?" +
+                    "appid=wxbde6b16acad84204&redirect_uri=http://staticweb.hnthyy.cn/wxserver/redirect/page2?" +
+                    "to=selectAssessmentPatient&response_type=code&scope=snsapi_base&state=1#wechat_redirect");
         } catch (IOException e) {
             throw new RuntimeException(e);
         }
     }
 
-    @PassToken
-    @GetMapping("/localPageTest")
-    public void localPageTest(@RequestParam("code") String code, HttpServletResponse response) {
-        try {
-            response.sendRedirect("http://172.16.30.26:4000/wxService/" + code);
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
 }

+ 49 - 50
src/main/java/thyyxxk/wxservice_server/controller/api/PowersiMiPayPlugin.java

@@ -3,7 +3,6 @@ package thyyxxk.wxservice_server.controller.api;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.tencent.mip.DataHandler;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpEntity;
@@ -31,6 +30,7 @@ import thyyxxk.wxservice_server.utils.DateUtil;
 import thyyxxk.wxservice_server.utils.ResultVoUtil;
 import thyyxxk.wxservice_server.utils.SnowFlakeId;
 import thyyxxk.wxservice_server.utils.TokenUtil;
+import thyyxxk.wxservice_server.utils.mip.DataHandler;
 
 import java.io.IOException;
 import java.math.BigDecimal;
@@ -43,40 +43,28 @@ public class PowersiMiPayPlugin {
     private final PowersiPluginDao dao;
     private final IdCardAnalyzeService idCardAnalyzeService;
     private final ThmzService thmzService;
-    private static final String MZ_API_URL = "http://172.16.30.26:1100/mobilePayApi";
-
-    // 移动支付测试环境
-//    private final static String chnlId = "1I14E7CSC05E4460C80A0000D6788E13";
-//    private final static String sm4key = "1I14E7CSC05F4460C80A000070CF4673";
-//    private final static String prvKey = "AOyLayJnHqXC56ENBW2vdfd5aPrncBOA3TK27LkvXHfI";
-//    private final static String pubKey = "BBVwpoYbrrguE9NEpi0PDKYqJKS5w7lksW1nLtNmVctgrli+B/sKs83tZQBlV3FTvTSaaHbxNidsBjsdisd0XDE=";
-
-    private final static String chnlId = "FBEBNX3X60526RPYJQ7PZ4CRPNZO8NC9";
-    private final static String sm4key = "SN7YCGQA4R1JJELBZNGKEMV3O4P9KF9F";
-    private final static String prvKey = "ATePKWH4x/ooLSoA5A5rxDrCgCbhFzPG/FvdqF2RkEI=";
-    private final static String pubKey = "BLaISfgVDY1OdD22WBSXO1z/PwHialH1lKxeB1SN7ZkCPEutbMCUpIJnl/009sXoXw7ubAHxfpHyn2aSgXAvkHI=";
 
+    private static final String MZ_API_URL = "http://172.16.30.26:1100/mobilePayApi";
 
-    private final DataHandler dataHandler = DataHandler.newInstance(chnlId, sm4key, pubKey, prvKey);
+    private final DataHandler dataHandler = DataHandler.newInstance();
 
     @Autowired
     public PowersiMiPayPlugin(PowersiPluginDao dao, IdCardAnalyzeService idCardAnalyzeService, ThmzService thmzService) throws IOException {
         this.dao = dao;
         this.idCardAnalyzeService = idCardAnalyzeService;
         this.thmzService = thmzService;
-        dataHandler.setSkipVerify(true);
     }
 
-    @PostMapping("/getOpenid")
-    public ResultVo<String> getOpenid(@RequestBody InsuinfoRequest request) throws Exception {
+    @PostMapping("/lockOrder")
+    public ResultVo<String> lockOrder(@RequestBody InsuinfoRequest request) throws Exception {
+        dao.lockOrder(request.getHisOrdNum());
         return ResultVoUtil.success(TokenUtil.getInstance().getUserOpenid());
     }
 
     private JSONObject decryptRequest(JSONObject body) throws Exception {
         body.put("code", 0);
-        String decrypt = dataHandler.processRspData(body.toJSONString());
-        JSONObject temp = JSONObject.parseObject(decrypt);
-        return temp.getJSONObject("data");
+        JSONObject decrypt = dataHandler.processRspData(body.toJSONString());
+        return decrypt.getJSONObject("data");
     }
 
     @PassToken
@@ -121,6 +109,9 @@ public class PowersiMiPayPlugin {
             List<Map<String, Object>> feeList = vo.getData();
             for (Map<String, Object> map : feeList) {
                 BillInfo billInfo = new BillInfo(map);
+                if (billInfo.getVipFlag() == 1) {
+                    continue;
+                }
                 String url = MZ_API_URL + "/writeMtReceipt?hisOrdNum=" + billInfo.getBizId();
                 String writeMtReceipt = new RestTemplate().getForObject(url, String.class);
                 if (Objects.equals(writeMtReceipt, "SUCCESS")) {
@@ -191,27 +182,39 @@ public class PowersiMiPayPlugin {
     public CommonResponse settleNotify(@RequestBody JSONObject body) throws Exception {
         JSONObject request = decryptRequest(body);
         PowersiMipSetlinfo setlinfo = dao.selectById(request.getString("platformOrderId"));
-        if (null != setlinfo) {
-            return new CommonResponse();
+        if (null == setlinfo) {
+            setlinfo = JSONObject.parseObject(request.toJSONString(), PowersiMipSetlinfo.class);
+            int insert = dao.insert(setlinfo);
+            if (insert == 1) {
+                saveMzOrder(setlinfo);
+                return new CommonResponse();
+            }
+            return new CommonResponse("HIS业务处理失败。");
         }
-        setlinfo = JSONObject.parseObject(request.toJSONString(), PowersiMipSetlinfo.class);
-        int insert = dao.insert(setlinfo);
-        if (insert == 1) {
-            SaveMzPayRequest saveMzPayRequest = new SaveMzPayRequest.Builder()
-                    .payTime(DateUtil.formatDatetime(setlinfo.getTraceTime()))
-                    .patCardNo(setlinfo.getMedOrgOrd().split("_")[0])
-                    .agtOrdNum(setlinfo.getThirdOrderId())
-                    .payAmt(setlinfo.getFeeSumamt())
-                    .fundpayAmt(setlinfo.getFundPay())
-                    .acctpayAmt(setlinfo.getPsnAcctPay())
-                    .couponAmt(BigDecimal.ZERO)
-                    .cashpayAmt(setlinfo.getOwnpayAmt())
-                    .hisOrdNum(setlinfo.getMedOrgOrd())
-                    .psOrdNum(setlinfo.getPlatformOrderId()).build();
-            thmzService.saveMzPay(saveMzPayRequest);
+        if (setlinfo.getMzSaved() == 0) {
+            saveMzOrder(setlinfo);
             return new CommonResponse();
         }
-        return new CommonResponse("接收通知失败。");
+        return new CommonResponse();
+    }
+
+    private void saveMzOrder(PowersiMipSetlinfo setlinfo) {
+        SaveMzPayRequest saveMzPayRequest = new SaveMzPayRequest.Builder()
+                .payTime(DateUtil.formatDatetime(setlinfo.getTraceTime()))
+                .patCardNo(setlinfo.getMedOrgOrd().split("_")[0])
+                .agtOrdNum(setlinfo.getThirdOrderId())
+                .payAmt(setlinfo.getFeeSumamt())
+                .fundpayAmt(setlinfo.getFundPay())
+                .acctpayAmt(setlinfo.getPsnAcctPay())
+                .couponAmt(BigDecimal.ZERO)
+                .cashpayAmt(setlinfo.getOwnpayAmt())
+                .hisOrdNum(setlinfo.getMedOrgOrd())
+                .psOrdNum(setlinfo.getPlatformOrderId())
+                .isNormalClinic(true).build();
+        ResultVo<String> res = thmzService.saveMzPay(saveMzPayRequest);
+        if (res.getCode() == ExceptionEnum.SUCCESS.getCode()) {
+            dao.updateMzSaved(setlinfo.getPlatformOrderId());
+        }
     }
 
     @PassToken
@@ -252,13 +255,10 @@ public class PowersiMiPayPlugin {
         HttpEntity<String> entity = new HttpEntity<>(body, headers);
         RestTemplate restTemplate = new RestTemplate();
         String encRes = restTemplate.postForObject(url, entity, String.class);
-        String decRes = dataHandler.processRspData(encRes);
-        JSONObject resObj = JSONObject.parseObject(decRes);
-
-        log.info("医保移动支付退款结果: {}", resObj);
-        Integer code = resObj.getInteger("code");
+        JSONObject decRes = dataHandler.processRspData(encRes);
+        Integer code = decRes.getInteger("code");
         if (null != code && code == 0) {
-            JSONObject data = resObj.getJSONObject("data");
+            JSONObject data = decRes.getJSONObject("data");
             OrdState state = OrdState.get(data.getString("refStatus"));
             if (null == state) {
                 return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR);
@@ -276,7 +276,7 @@ public class PowersiMiPayPlugin {
             }
             return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, data.getString("failMsg"));
         }
-        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, resObj.getString("message"));
+        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, decRes.getString("message"));
     }
 
     private PowersiMipSetlinfo getRefundableSetl(String id) {
@@ -319,11 +319,10 @@ public class PowersiMiPayPlugin {
         HttpEntity<String> entity = new HttpEntity<>(body, headers);
         RestTemplate restTemplate = new RestTemplate();
         String encRes = restTemplate.postForObject(url, entity, String.class);
-        String decRes = dataHandler.processRspData(encRes);
-        JSONObject resObj = JSONObject.parseObject(decRes);
-        Integer code = resObj.getInteger("code");
+        JSONObject decRes = dataHandler.processRspData(encRes);
+        Integer code = decRes.getInteger("code");
         if (null != code && code == 0) {
-            JSONObject data = resObj.getJSONObject("data");
+            JSONObject data = decRes.getJSONObject("data");
             data.remove("hiExtData");
             OrdState state = OrdState.get(data.getString("refdStatus"));
             if (null == state) {
@@ -333,7 +332,7 @@ public class PowersiMiPayPlugin {
             dao.updateRefundState(refId, state);
             return ResultVoUtil.success(state.toString());
         }
-        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, resObj.getString("message"));
+        return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, decRes.getString("message"));
     }
 
 }

+ 8 - 0
src/main/java/thyyxxk/wxservice_server/dao/api/PowersiPluginDao.java

@@ -12,6 +12,11 @@ import java.util.List;
 
 @Mapper
 public interface PowersiPluginDao extends BaseMapper<PowersiMipSetlinfo> {
+
+    @Update("update mz_order_lock set lock_flag=1,update_time=getdate() " +
+            "where his_order_num=#{hisOrdNum}")
+    void lockOrder(String hisOrdNum);
+
     @Select("select rtrim(patient_id) from mz_patient_mi where social_no=#{id}")
     List<String> selectPatientCount(String id);
 
@@ -26,4 +31,7 @@ public interface PowersiPluginDao extends BaseMapper<PowersiMipSetlinfo> {
 
     @Update("update powersi_mip_setlinfo set ord_state=#{state} where platform_refd_id=#{refdId}")
     void updateRefundState(String refdId, OrdState state);
+
+    @Update("update powersi_mip_setlinfo set mz_saved=1 where platform_order_id=#{id}")
+    void updateMzSaved(String id);
 }

+ 5 - 0
src/main/java/thyyxxk/wxservice_server/entity/medinsmobilepay/frompowersiplugin/request/PowersiMipSetlinfo.java

@@ -195,4 +195,9 @@ public class PowersiMipSetlinfo {
 	 * 平台退费订单号,后续可根据此订单号查退费状态
 	 * */
 	private String platformRefdId;
+
+	/**
+	 * 门诊处方是否已保存(0-否,1-是)
+	 * */
+	private Integer mzSaved;
 }

+ 3 - 0
src/main/java/thyyxxk/wxservice_server/entity/medinsmobilepay/frompowersiplugin/response/BillInfo.java

@@ -19,6 +19,8 @@ public class BillInfo {
     private BigDecimal medfeeSumamt;
     private String deptName;
     private String deptId;
+    //  0-普通病人;1-股东卡已打折,不进医保;2-股东卡不打折,需要进医保
+    private Integer vipFlag;
 
     public BillInfo() {
     }
@@ -31,5 +33,6 @@ public class BillInfo {
         totalAmt = totalAmt.split("\\.")[0];
         this.medfeeSumamt = DecimalTool.moneyFenToYuan(Integer.parseInt(totalAmt));
         this.deptName = hisCharge.get("deptName").toString();
+        this.vipFlag = (Integer) hisCharge.get("vipFlag");
     }
 }

+ 1 - 0
src/main/java/thyyxxk/wxservice_server/factory/thmz/ThmzService.java

@@ -277,6 +277,7 @@ public class ThmzService {
                 JSON.toJSON(request), JSON.toJSON(mzFeeResponse));
         mzFeeResponse = null == mzFeeResponse ? new SaveMzFeeResponse() : mzFeeResponse;
         if (mzFeeResponse.getResultCode() == 0) {
+
             return ExceptionEnum.SUCCESS;
         }
         if (mzFeeResponse.getResultMessage().contains("获取缴费流水号失败")) {

+ 135 - 0
src/main/java/thyyxxk/wxservice_server/utils/mip/CommonUtil.java

@@ -0,0 +1,135 @@
+package thyyxxk.wxservice_server.utils.mip;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.serializer.PropertyFilter;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import jdk.nashorn.internal.objects.NativeString;
+
+public class CommonUtil {
+    private static final SerializerFeature[] defaultFeatures;
+    private static final SerializerFeature[] stringFeatures;
+    private static final PropertyFilter filter;
+
+    public CommonUtil() {}
+
+    private static boolean isBaseDataType(Class clazz) {
+        return clazz.equals(String.class) || clazz.equals(Integer.class) || clazz.equals(Byte.class) || clazz.equals(Long.class) || clazz.equals(Double.class) || clazz.equals(Float.class) || clazz.equals(Character.class) || clazz.equals(Short.class) || clazz.equals(BigDecimal.class) || clazz.equals(BigInteger.class) || clazz.equals(Boolean.class) || clazz.equals(Date.class) || clazz.isPrimitive();
+    }
+
+    public static String getSignStr(String appSecret, Map<String, Object> param) {
+        return getSignStr(appSecret, param, false);
+    }
+
+    public static String getSignStr(String appSecret, Map<String, Object> param, boolean stringValue) {
+        JSONObject jsonObject = new JSONObject(param);
+        return getSignStr(appSecret, jsonObject, stringValue);
+    }
+
+    public static String getSignStr(String appSecret, JSONObject param, boolean stringValue) {
+        StringBuilder sb = new StringBuilder();
+        String[] sortKeys = param.keySet().stream().sorted().toArray(String[]::new);
+
+        for (String key : sortKeys) {
+            Object val = param.get(key);
+            if (null != val && !Objects.equals(key, "signData") && !Objects.equals(key, "encData") && !Objects.equals(key, "extra")) {
+                String value;
+                if (isBaseDataType(val.getClass())) {
+                    value = val.toString();
+                } else {
+                    value = JSON.toJSONString(val, filter, stringValue ? stringFeatures : defaultFeatures);
+                }
+
+                if (!value.trim().isEmpty()) {
+                    if (sb.length() > 0) {
+                        sb.append("&");
+                    }
+
+                    sb.append(key);
+                    sb.append("=");
+                    sb.append(value);
+                }
+            }
+        }
+
+        sb.append("&key=").append(appSecret);
+        return sb.toString();
+    }
+
+    public static String stringToHexString(String s) {
+        String str = "";
+
+        for(int i = 0; i < s.length(); ++i) {
+            int ch = s.charAt(i);
+            String s4 = Integer.toHexString(ch);
+            str = str + s4;
+        }
+
+        return str;
+    }
+
+    public static String byteArrayToHex(byte[] byteArray) {
+        char[] hexDigits = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+        char[] resultCharArray = new char[byteArray.length * 2];
+        int index = 0;
+        byte[] var4 = byteArray;
+        int var5 = byteArray.length;
+
+        for(int var6 = 0; var6 < var5; ++var6) {
+            byte b = var4[var6];
+            resultCharArray[index++] = hexDigits[b >>> 4 & 15];
+            resultCharArray[index++] = hexDigits[b & 15];
+        }
+
+        return (new String(resultCharArray)).toUpperCase();
+    }
+
+    public static String byteToHex(byte[] b) {
+        if (b == null) {
+            throw new IllegalArgumentException("Argument b ( byte array ) is null! ");
+        } else {
+            String hs = "";
+            String stmp = "";
+
+            for(int n = 0; n < b.length; ++n) {
+                stmp = Integer.toHexString(b[n] & 255);
+                if (stmp.length() == 1) {
+                    hs = hs + "0" + stmp;
+                } else {
+                    hs = hs + stmp;
+                }
+            }
+
+            return hs.toUpperCase();
+        }
+    }
+
+    public static List<String> getStrList(String inputString, int length, int size) {
+        List<String> list = new ArrayList();
+
+        for(int index = 0; index < size; ++index) {
+            String childStr = NativeString.substring(inputString, index * length, (index + 1) * length);
+            list.add(childStr);
+        }
+
+        return list;
+    }
+
+    static {
+        defaultFeatures = new SerializerFeature[]{SerializerFeature.MapSortField};
+        stringFeatures = new SerializerFeature[]{SerializerFeature.MapSortField, SerializerFeature.WriteNonStringValueAsString};
+        filter = new PropertyFilter() {
+            public boolean apply(Object source, String name, Object value) {
+                return !Objects.equals(value, (Object)null) && (!value.getClass().equals(String.class) || !Objects.equals(value, ""));
+            }
+        };
+    }
+}
+

+ 80 - 0
src/main/java/thyyxxk/wxservice_server/utils/mip/DataHandler.java

@@ -0,0 +1,80 @@
+package thyyxxk.wxservice_server.utils.mip;
+
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.Date;
+
+import lombok.extern.slf4j.Slf4j;
+import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
+import thyyxxk.wxservice_server.config.exception.BizException;
+
+@Slf4j
+public class DataHandler {
+    private final static String appID = "FBEBNX3X60526RPYJQ7PZ4CRPNZO8NC9";
+    private final static String secret = "SN7YCGQA4R1JJELBZNGKEMV3O4P9KF9F";
+    private final static String prvKey = "ATePKWH4x/ooLSoA5A5rxDrCgCbhFzPG/FvdqF2RkEI=";
+    private final static String pubKey = "BLaISfgVDY1OdD22WBSXO1z/PwHialH1lKxeB1SN7ZkCPEutbMCUpIJnl/009sXoXw7ubAHxfpHyn2aSgXAvkHI=";
+    Base64.Decoder decoder = Base64.getDecoder();
+    private final byte[] encryptKeys;
+    private final String privateKeys;
+    SM2Util sm2 = new SM2Util();
+
+    private DataHandler() {
+        this.encryptKeys = SM4Util.encryptEcb(CommonUtil.stringToHexString(appID.substring(0, 16)), secret).substring(0, 16).toUpperCase().getBytes();
+        this.privateKeys = CommonUtil.byteArrayToHex(this.decoder.decode(prvKey));
+    }
+
+    public static DataHandler newInstance() {
+        return new DataHandler();
+    }
+
+    public String buildReqData(JSONObject data) throws Exception {
+        log.info("医保移动支付加密:{}", data);
+        JSONObject reqJSON = new JSONObject();
+        String version = "2.0.1";
+        reqJSON.put("version", version);
+        reqJSON.put("encType", "SM4");
+        reqJSON.put("signType", "SM2");
+        reqJSON.put("appId", appID);
+        reqJSON.put("timestamp", (new Date()).getTime());
+        reqJSON.put("extra", null);
+        reqJSON.put("data", data);
+        String signStr = CommonUtil.getSignStr(secret, reqJSON);
+        String signData = this.sm2.sign(signStr, privateKeys);
+        reqJSON.put("signData", signData);
+        byte[] dataBytes = data.toString(new SerializerFeature[]{SerializerFeature.WriteMapNullValue}).getBytes(StandardCharsets.UTF_8);
+        byte[] encDataBytes = SM4Util.encrypt_Ecb_Padding(this.encryptKeys, dataBytes);
+        String encData = ByteUtils.toHexString(encDataBytes);
+        reqJSON.put("encData", encData);
+        reqJSON.remove("data");
+        return reqJSON.toString();
+    }
+
+    public String buildReqData(String objData) throws Exception {
+        return this.buildReqData(JSONObject.parseObject(objData));
+    }
+
+    public JSONObject processRspData(String rspData) throws Exception {
+        JSONObject rspJSON = JSONObject.parseObject(rspData);
+        Integer codeObj = rspJSON.getInteger("code");
+        if (codeObj != null && codeObj == 0) {
+            String encData = rspJSON.get("encData").toString();
+            JSONObject dataObject;
+            try {
+                byte[] cipherData = ByteUtils.fromHexString(encData);
+                byte[] cipherByte = SM4Util.decrypt_Ecb_Padding(this.encryptKeys, cipherData);
+                String dEncData = new String(cipherByte, StandardCharsets.UTF_8);
+                dataObject = JSONObject.parseObject(dEncData);
+            } catch (Exception var9) {
+                throw new BizException("医保移动支付解密出错。");
+            }
+            rspJSON.put("data", dataObject);
+            rspJSON.remove("encData");
+            rspJSON.remove("signData");
+            log.info("医保移动支付解密:{}", rspJSON);
+        }
+        return rspJSON;
+    }
+}

+ 154 - 0
src/main/java/thyyxxk/wxservice_server/utils/mip/SM2Util.java

@@ -0,0 +1,154 @@
+package thyyxxk.wxservice_server.utils.mip;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Base64;
+import java.util.List;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1SequenceParser;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.gm.GMNamedCurves;
+import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
+import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.spec.ECParameterSpec;
+import org.bouncycastle.jce.spec.ECPrivateKeySpec;
+import org.bouncycastle.jce.spec.ECPublicKeySpec;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.util.encoders.Hex;
+import thyyxxk.wxservice_server.config.exception.BizException;
+
+public class SM2Util {
+    private BouncyCastleProvider provider;
+    private X9ECParameters parameters;
+    private ECParameterSpec ecParameterSpec;
+    private KeyFactory keyFactory;
+    Base64.Decoder decoder = Base64.getDecoder();
+    Base64.Encoder encoder = Base64.getEncoder();
+
+    public SM2Util() {
+        try {
+            this.provider = new BouncyCastleProvider();
+            this.parameters = GMNamedCurves.getByName("sm2p256v1");
+            this.ecParameterSpec = new ECParameterSpec(this.parameters.getCurve(), this.parameters.getG(), this.parameters.getN(), this.parameters.getH());
+            this.keyFactory = KeyFactory.getInstance("EC", this.provider);
+        } catch (Exception var2) {
+            var2.printStackTrace();
+        }
+
+    }
+
+    public String sign(String plainText, String prvKey) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException, IOException {
+        Signature signature = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString(), this.provider);
+        BigInteger bigInteger = new BigInteger(prvKey, 16);
+        BCECPrivateKey privateKey = (BCECPrivateKey)this.keyFactory.generatePrivate(new ECPrivateKeySpec(bigInteger, this.ecParameterSpec));
+        signature.initSign(privateKey);
+        signature.update(plainText.getBytes(StandardCharsets.UTF_8));
+        String signStr = Base64.getEncoder().encodeToString(signature.sign());
+        signStr = (new BigInteger(this.decoder.decode(signStr))).toString(16);
+        String derStr = SM2Util.SM2SignAsn1.parseSm2SignAsn1Object(signStr);
+        byte[] hexStr = Hex.decode(derStr);
+        return this.encoder.encodeToString(hexStr);
+    }
+
+    public boolean verify(String plainText, String signatureValue, String pubKey) throws NoSuchAlgorithmException {
+        Signature signature = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString(), this.provider);
+
+        try {
+            ECPoint ecPoint = this.parameters.getCurve().decodePoint(Hex.decode(pubKey));
+            BCECPublicKey key = (BCECPublicKey)this.keyFactory.generatePublic(new ECPublicKeySpec(ecPoint, this.ecParameterSpec));
+            signature.initVerify(key);
+            signature.update(plainText.getBytes(StandardCharsets.UTF_8));
+            byte[] signDataByte = this.decoder.decode(signatureValue);
+            String sigDataHex = Hex.toHexString(signDataByte);
+            List<String> list = CommonUtil.getStrList(sigDataHex, 64, 2);
+            String sm2SignAsn1 = SM2Util.SM2SignAsn1.buildSm2SignAsn1Object(new BigInteger((String)list.get(0), 16), new BigInteger((String)list.get(1), 16));
+            byte[] sm2SignAsn1Byte = Hex.decode(sm2SignAsn1);
+            String sm2SignAsn1ByteText = this.encoder.encodeToString(sm2SignAsn1Byte);
+            return signature.verify(this.decoder.decode(sm2SignAsn1ByteText));
+        } catch (Exception var13) {
+            System.out.println(var13);
+            var13.printStackTrace();
+            return false;
+        }
+    }
+
+    public static class SM2SignAsn1 extends ASN1Object {
+        private final ASN1Integer int1;
+        private final ASN1Integer int2;
+
+        public SM2SignAsn1(ASN1Integer int1, ASN1Integer int2) {
+            this.int1 = int1;
+            this.int2 = int2;
+        }
+
+        public ASN1Primitive toASN1Primitive() {
+            ASN1EncodableVector vector = new ASN1EncodableVector();
+            vector.add(this.int1);
+            vector.add(this.int2);
+            return new DERSequence(vector);
+        }
+
+        public static String buildSm2SignAsn1Object(BigInteger int1, BigInteger int2) {
+            String res = null;
+
+            try {
+                SM2Util.SM2SignAsn1 sm2SignAsn1 = new SM2Util.SM2SignAsn1(new ASN1Integer(int1), new ASN1Integer(int2));
+                byte[] encoded = sm2SignAsn1.getEncoded();
+                res = CommonUtil.byteToHex(encoded);
+            } catch (Exception var5) {
+                var5.printStackTrace();
+            }
+
+            return res;
+        }
+
+        public static String parseSm2SignAsn1Object(String hexStr) {
+            byte[] hexByte = Hex.decode(hexStr);
+            String encodedText = Base64.getEncoder().encodeToString(hexByte);
+            StringBuilder sb = new StringBuilder();
+            byte[] data = org.bouncycastle.util.encoders.Base64.decode(encodedText);
+            ASN1InputStream ais = new ASN1InputStream(data);
+
+            try {
+                while(true) {
+                    ASN1Primitive primitive;
+                    do {
+                        if ((primitive = ais.readObject()) == null) {
+                            return sb.toString().replace("#", "");
+                        }
+                    } while(!(primitive instanceof ASN1Sequence));
+
+                    ASN1Sequence sequence = (ASN1Sequence)primitive;
+                    ASN1SequenceParser parser = sequence.parser();
+
+                    ASN1Encodable encodable;
+                    while((encodable = parser.readObject()) != null) {
+                        primitive = encodable.toASN1Primitive();
+                        String temp = String.valueOf(primitive);
+                        String s = String.format("%064x", new BigInteger(temp));
+                        sb.append(s);
+                    }
+                }
+            } catch (Exception var12) {
+                throw new BizException("ERROR_CODE_ASN1_ERROR");
+            }
+        }
+    }
+}

+ 50 - 0
src/main/java/thyyxxk/wxservice_server/utils/mip/SM4Util.java

@@ -0,0 +1,50 @@
+package thyyxxk.wxservice_server.utils.mip;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
+import java.security.Key;
+import java.security.Security;
+
+public class SM4Util {
+
+    public SM4Util() {}
+
+    private static Cipher generateEcbCipher(int mode, byte[] key) throws Exception {
+        Cipher cipher = Cipher.getInstance("SM4/ECB/PKCS7Padding", "BC");
+        Key sm4Key = new SecretKeySpec(key, "SM4");
+        cipher.init(mode, sm4Key);
+        return cipher;
+    }
+
+    public static String encryptEcb(String hexKey, String paramStr) {
+        try {
+            String cipherText = "";
+            byte[] keyData = ByteUtils.fromHexString(hexKey);
+            byte[] srcData = paramStr.getBytes(StandardCharsets.UTF_8);
+            byte[] cipherArray = encrypt_Ecb_Padding(keyData, srcData);
+            cipherText = ByteUtils.toHexString(cipherArray);
+            return cipherText;
+        } catch (Exception var6) {
+            return paramStr;
+        }
+    }
+
+    public static byte[] encrypt_Ecb_Padding(byte[] key, byte[] data) throws Exception {
+        Cipher cipher = generateEcbCipher(1, key);
+        return cipher.doFinal(data);
+    }
+
+    public static byte[] decrypt_Ecb_Padding(byte[] key, byte[] cipherText) throws Exception {
+        Cipher cipher = generateEcbCipher(2, key);
+        return cipher.doFinal(cipherText);
+    }
+
+    static {
+        Security.addProvider(new BouncyCastleProvider());
+    }
+
+}

+ 2 - 3
src/main/resources/application.yml

@@ -47,9 +47,8 @@ siMzApiUrl: http://172.16.30.26:1100/mzFee
 chronicUrl: http://demo.hnthyy.cn:8706/chronicDisease
 #chronicUrl: http://localhost:8706/chronicDisease
 
-hrgApiUrl: http://demo.hnthyy.cn:8089/thmz/api/v1
-#hrgApiUrl: http://172.16.30.119:8089/thmz/api/v1
-#hrgApiUrl: http://172.16.32.160:81/thmz/api/v1
+#hrgApiUrl: http://demo.hnthyy.cn:8089/thmz/api/v1
+hrgApiUrl: http://172.16.30.119:8089/thmz/api/v1
 
 inspectionUrl: http://172.16.32.178:622/pushservice.asmx?wsdl
 physicalCheck: http://172.16.32.183:8888/bdp/dataservice/api/