最近在做一个澳门的商城项目,其中需要跟当地的工商银行对接支付,其中的提交支付时,工商银行的加密有自己加密程序,然而他们只提供了JAVA和C 语言的DEMO,并没有PHP的DEMO,甚至连PHP的扩展也说没有,一时让我陷入了困境,不知道怎解决,于是我在百度 谷歌上寻找解决方法。
其实这澳门提供的接口的加密方式跟国内大陆的一致,也是用infosec扩展的程序进行加密,大陆的一些开发人员对接接口是直接把JAVA转化成PHP,不过必须的当然是相关的PHP扩展。不过,让我失望的是,当我问工作人员有没有PHP扩展时,他却一问三不知,只有JAVA版本的。而网友分享的PHP拓展,一来不安全,二来只有PHP5.6的版本,而我们服务器已经升级到PHP7了,不知道能否兼容。因此,保守起见,最终放弃了该做法。
(该方法可参考链接:https://blog.csdn.net/weixin_41750160/article/details/83341199)
既然他们提供了java的demo,其实应用起来也不难。但是需要的是搭建javaWeb的环境,并且把demo部署好,我们让php程序加密时候调用一下自己的做的java 加密接口就好了。最终,我选择了该方法。
(该方法可参考链接:https://www.cnblogs.com/weishuan/p/8372063.html)
该过程不熟悉的朋友,可以按照教程一步步来,值得注意的是,tomcat的端口是8080,其实根据我们的需求,我们只需要自己的PHP程序所在服务器能请求到就行,也就是说localhost能访问或者固定IP就好了,以防给黑客多一个攻击的入口,因此该端口可以不开放或者限制IP访问。
可以参考https://blog.csdn.net/lcyaiym/article/details/76696192
其实工商银行对接人一般会提供接口介绍的PPT给你,有加密方法的demo,但是也还没达到开箱即用的程度,因此我分享一下我自己的写的java demo给大家参考。请根据自己的文件路径进行修改,注释部分是调试的,如果返回不成功,可以去掉注释进行分步调试。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.com.infosec.icbc.ReturnValue;
/**
* Servlet implementation class getSign
*/
@WebServlet("/getSign")
public class getSign extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public getSign() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
String type = request.getParameter("type"); //區分是調用哪個函數
String merCerFileKeyPath = "/var/www/opencart/v3.0/signicbc/icbcOpayTest.key"; //商户秘钥所在绝对路径
String merCerFileCrtPath = "/var/www/opencart/v3.0/signicbc/icbcOpayTest.crt"; //商户证书所在绝对路径
if (type != null) {
String interfaceName = request.getParameter("interfaceName");
String interfaceVersion = request.getParameter("interfaceVersion");
String areaCode = request.getParameter("areaCode");
String merID = request.getParameter("merID");
String merAcct = request.getParameter("merAcct");
String merURL = request.getParameter("merURL");
String notifyType = request.getParameter("nType");
String orderid = request.getParameter("orderid");
String amount = request.getParameter("amount");
String curType = request.getParameter("curType");
String resultType = request.getParameter("resultType");
String orderDate = request.getParameter("orderDate");
String keyPass = request.getParameter("keyPass");
/*
out.println("---interfaceName" + interfaceName);
out.println("---interfaceVersion" + interfaceVersion);
out.println("---areaCode" + areaCode);
out.println("---merID" + merID);
out.println("---merAcct" + merAcct);
out.println("---merURL" + merURL);
out.println("---notifyType" + notifyType);
out.println("---orderid" + orderid);
out.println("---amount" + amount);
out.println("---curType" + curType);
out.println("---resultType" + resultType);
out.println("---orderDate" + orderDate);
out.println("---keyPass" + keyPass);
*/
StringBuilder tranData = new StringBuilder();
tranData.append(interfaceName).append(interfaceVersion).append(areaCode).append(merID).append(merAcct).append(merURL).append(notifyType).append(orderid).append(amount).append(curType).append(resultType).append(orderDate);
//String MerSign = getMerSignMsgBase64(tranData.toString(), merCerFileCrtPath, keyPass);StringBuilder
//out.println("IcbcOpayFileReader.getMerSignMsgBase64:"+tranData.toString());
byte[] tranByteSrc = tranData.toString().getBytes();
char[] keyPasss = keyPass.toCharArray();
File merSineFile = new File(merCerFileKeyPath);
FileInputStream fileInputStream;
try {
fileInputStream = new FileInputStream(merSineFile.getAbsolutePath());
byte[] sineBytes = new byte[fileInputStream.available()];
fileInputStream.read(sineBytes);
fileInputStream.close();
byte[] sign =ReturnValue.sign(tranByteSrc,tranByteSrc.length,sineBytes,keyPasss);
if(sign ==null){
out.println("-----sign return is null");
out.println("-----sign tranByteSrc.length is"+tranByteSrc.length);
out.println("-----sign keyPasss is"+keyPasss);
}
byte[] EncSign = ReturnValue.base64enc(sign);
String merSignMsgBase64=new String(EncSign,"UTF-8").toString();
merSignMsgBase64= merSignMsgBase64.replace("\n", "");
merSignMsgBase64= merSignMsgBase64.replace("\r", "");
out.print(merSignMsgBase64);
} catch (Exception e) {
System.out.println("getMerSignMsgBase64"+e.getMessage());
e.printStackTrace();
}
}else {
String merCertBase64 = getMerCertBase64(merCerFileCrtPath);
out.print(merCertBase64);
}
}
public static String getMerCertBase64(String merCerFilePath) {
File merCerFile = new File(merCerFilePath);
FileInputStream fileInputStream;
try {
fileInputStream = new FileInputStream(merCerFile.getAbsolutePath());
System.out.println(merCerFile.getAbsolutePath());
byte[] bytes = new byte[fileInputStream.available()];
fileInputStream.read(bytes);
fileInputStream.close();
byte[] EncCerts=ReturnValue.base64enc(bytes);
String merCertBase64=new String(EncCerts).toString();
merCertBase64= merCertBase64.replace("\n", "");
merCertBase64= merCertBase64.replace("\r", "");
System.out.println("IcbcOpayFileReader.getMerCertBase64:"+merCertBase64);
return merCertBase64;
} catch (FileNotFoundException e) {
System.out.println("getMerCertBase64"+e.getMessage());
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
private String getParameter(HttpServletRequest request, String paramString)
{
String param = paramString.replace("&","");
String v = request.getParameter(param);
if (v == null)
v="";
System.out.println(paramString + "=" + v);
return paramString + "=" + v + "&";
}
private String verifySign(String msg, String signMsg, String pubKeyFile){
String ENCODING = "utf-8";
try
{
// 读取工行的公钥
FileInputStream fileKey = new FileInputStream(pubKeyFile);
byte[] cert = new byte[fileKey.available()];
fileKey.read(cert);
fileKey.close();
// 读取明文,密文
byte[] byteSrc = msg.getBytes(ENCODING);
byte[] sign = ReturnValue.base64dec(signMsg.getBytes(ENCODING));
// 验证,正常返回0,失败返回1
int verifySign = ReturnValue.verifySign(byteSrc, byteSrc.length, cert, sign);
System.out.println("RetCode = " + verifySign);
if (verifySign == 0)
return "true";
return "verify_false"+verifySign;
} catch (Exception e){
e.printStackTrace();
return "try_false";
}
}
}
请求工商银行的支付接口时,主要加密的两个参数主要是订单签名数据和商城证书公钥,我的java接口demo中,传参type=1时是指订单签名数据加密(同时需要传入加密订单参数),而不传type值时,是指商城证书公钥加密。
例子如下:
订单签名数据加密:
http://localhost:8080/icbc/getSign?type=1&interfaceName=ICBC_MYEBANK_B2C&interfaceVersion=3.0.0.0&areaCode=0119&merID=0119EC20000741&merAcct=0119100000001017824&merURL=http://www.test.com/test123&nType=HS&orderid=20190716121050883909&amount=1230&curType=MOP&resultType=1&orderDate=20190716121050&keyPass=12345678
商城证书公钥加密:
http://localhost:8080/icbc/getSign
返回内容均为base64格式的加密内容。
最后,用PHP整合请求支付接口进行支付页面跳转,在此我也提供我的测试demo给大家参考。
(下载地址:https://download.csdn.net/download/tim_phper/11364454)
其实跨语言也没有想象中那么困难,动手试一试,你可以能会发现其实也很容易。过程可能遇到很多坑,可是你会发现收获真的不少的!