1.修改了签名和验证签名方式

This commit is contained in:
Actinia-517
2017-12-07 22:58:42 +08:00
parent 9bb185286b
commit e2649abb79
3 changed files with 133 additions and 263 deletions

View File

@@ -61,40 +61,6 @@ public class CertUtil {
/**
* 请求报文签名(使用配置文件中配置的私钥证书或者对称密钥签名)<br>
* 功能:对请求报文进行签名,并计算赋值certid,signature字段并返回<br>
* @param reqData 请求报文map<br>
* @param encoding 上送请求报文域encoding字段的值<br>
* @return 签名后的map对象<br>
*/
public static Map<String, String> sign(Map<String, String> reqData,String encoding) {
reqData = filterBlank(reqData);
SDKUtils.signParams(reqData, encoding);
return reqData;
}
/**
* 过滤请求报文中的空字符串或者空字符串
* @param contentData
* @return
*/
public static Map<String, String> filterBlank(Map<String, String> contentData){
Map<String, String> submitFromData = new HashMap<String, String>();
Set<String> keyset = contentData.keySet();
for(String key:keyset){
String value = contentData.get(key);
if (StringUtils.isNotBlank(value)) {
// 对value值进行去除前后空处理
submitFromData.put(key, value.trim());
}
}
return submitFromData;
}
static {
init();
}

View File

@@ -1,204 +0,0 @@
package com.egzosn.pay.union.SDK;/**
* Description
* author: Fuzx
* date: 2017/11/27 0027
*/
import com.egzosn.pay.common.util.sign.SecureUtil;
import com.egzosn.pay.common.util.sign.SignUtils;
import com.egzosn.pay.common.util.sign.encrypt.Base64;
import com.egzosn.pay.common.util.sign.encrypt.RSA;
import com.egzosn.pay.common.util.sign.encrypt.SHA256;
import com.egzosn.pay.common.util.str.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.*;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.zip.Inflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import static com.egzosn.pay.union.SDK.SDKConstants.*;
/**
* @author Actinia
* @email hayesfu@qq.com
* @create 2017 2017/11/27 0027
*/
public class SDKUtils {
//日志
protected static final Log log = LogFactory.getLog(SDKUtils.class);
/**
* 验证签名
*
* @param resData
* 返回报文数据
* @param encoding
* 编码格式
* @return
*/
public static boolean validate(Map<String, Object> resData, String encoding) {
log.info("验签处理开始");
if (StringUtils.isEmpty(encoding)) {
encoding = "UTF-8";
}
String signMethod = resData.get(SDKConstants.param_signMethod).toString();
String version = resData.get(SDKConstants.param_version).toString();
if (SIGNMETHOD_RSA.equals(signMethod) || VERSION_1_0_0.equals(version) || VERSION_5_0_1.equals(version)) {
// 获取返回报文的版本号
if (VERSION_5_0_0.equals(version) || VERSION_1_0_0.equals(version) || VERSION_5_0_1.equals(version)) {
String stringSign = resData.get(SDKConstants.param_signature).toString();
log.info("签名原文:["+stringSign+"]");
// 从返回报文中获取certId 然后去证书静态Map中查询对应验签证书对象
String certId = resData.get(SDKConstants.param_certId).toString();
log.info("对返回报文串验签使用的验签公钥序列号:["+certId+"]");
// 将Map信息转换成key1=value1&key2=value2的形式
String stringData = SignUtils.parameterText(resData);
log.info("待验签返回报文串:["+stringData+"]");
try {
// 验证签名需要用银联发给商户的公钥证书.
return SecureUtil.validateSignBySoft(CertUtil.getValidatePublicKey(certId), Base64.decode(stringSign),
SecureUtil.sha1X16(stringData, encoding));
} catch (UnsupportedEncodingException e) {
log.error(e.getMessage(), e);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
} else if (VERSION_5_1_0.equals(version)) {
// 1.从返回报文中获取公钥信息转换成公钥对象
String strCert = resData.get(SDKConstants.param_signPubKeyCert).toString();
log.info("验签公钥证书:["+strCert+"]");
X509Certificate x509Cert = CertUtil.genCertificateByStr(strCert);
if(x509Cert == null) {
log.error("convert signPubKeyCert failed");
return false;
}
// 2.验证证书链
if (!CertUtil.verifyCertificate(x509Cert)) {
log.error("验证公钥证书失败,证书信息:["+strCert+"]");
return false;
}
// 3.验签
String stringSign = resData.get(SDKConstants.param_signature).toString();
log.info("签名原文:["+stringSign+"]");
// 将Map信息转换成key1=value1&key2=value2的形式
String stringData = SignUtils.parameterText(resData);
log.info("待验签返回报文串:["+stringData+"]");
try {
// 验证签名需要用银联发给商户的公钥证书.
boolean result = SecureUtil.validateSignBySoft256(x509Cert
.getPublicKey(), Base64.decode(stringSign
), SHA256.sign(
stringData, "", encoding).getBytes());
log.info("验证签名" + (result? "成功":"失败"));
return result;
} catch (UnsupportedEncodingException e) {
log.error(e.getMessage(), e);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
} else if (SIGNMETHOD_SHA256.equals(signMethod)) {
// 1.进行SHA256验证
String stringSign = resData.get(SDKConstants.param_signature).toString();
log.info("签名原文:["+stringSign+"]");
// 将Map信息转换成key1=value1&key2=value2的形式
String stringData = SignUtils.parameterText(resData);
log.info("待验签返回报文串:["+stringData+"]");
String strBeforeSha256 = stringData
+ SDKConstants.AMPERSAND
+ SecureUtil.sha256X16Str(SDKConfig.getConfig()
.getSecureKey(), encoding);
String strAfterSha256 = SecureUtil.sha256X16Str(strBeforeSha256,
encoding);
boolean result = stringSign.equals(strAfterSha256);
log.info("验证签名" + (result? "成功":"失败"));
return result;
} else if (SIGNMETHOD_SM3.equals(signMethod)) {
// 1.进行SM3验证
String stringSign = resData.get(SDKConstants.param_signature).toString();
log.info("签名原文:["+stringSign+"]");
// 将Map信息转换成key1=value1&key2=value2的形式
String stringData = SignUtils.parameterText(resData);
log.info("待验签返回报文串:["+stringData+"]");
String strBeforeSM3 = stringData
+ SDKConstants.AMPERSAND
+ SecureUtil.sm3X16Str(SDKConfig.getConfig()
.getSecureKey(), encoding);
String strAfterSM3 = SecureUtil
.sm3X16Str(strBeforeSM3, encoding);
boolean result = stringSign.equals(strAfterSM3);
log.info("验证签名" + (result? "成功":"失败"));
return result;
}
return false;
}
/**
* 对参数加密
* @param data
* @param encoding
* @return
*/
public static boolean signParams(Map<String, String> data,String encoding){
if (StringUtils.isBlank(encoding)) {
encoding = "UTF-8";
}
String signMethod = data.get(SDKConstants.param_signMethod);
String version = data.get(SDKConstants.param_version);
if(StringUtils.isBlank(signMethod)){
log.info("银联签名方式不能为空");
return false;
}
if(StringUtils.isBlank(version)){
log.info("版本号不能为空");
return false;
}
if (SIGNMETHOD_RSA.equals(signMethod)|| VERSION_1_0_0.equals(version) || SDKConstants.VERSION_5_0_1.equals(version)) {
if (SDKConstants.VERSION_5_0_0.equals(version) || VERSION_1_0_0.equals(version) || SDKConstants.VERSION_5_0_1.equals(version)) {
data.put(SDKConstants.param_certId, CertUtil.getSignCertId());
String stringData = SignUtils.parameterText(data);
String stringSign = null;
try {
// 通过SHA1进行摘要并转16进制
byte[] signDigest = SecureUtil
.sha1X16(stringData, encoding);
stringSign = RSA.sign(signDigest, CertUtil.getSignCertPrivateKey());
// 设置签名域值
data.put(SDKConstants.param_signature, stringSign);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}else if (SDKConstants.SIGNMETHOD_SHA256.equals(signMethod)) {
String stringData = SignUtils.parameterText(data);
String strBeforeSha256 = stringData
+ SDKConstants.AMPERSAND
+ SecureUtil.sha256X16Str(SDKConfig.getConfig().getSecureKey(), encoding);
String strAfterSha256 = SecureUtil.sha256X16Str(strBeforeSha256,
encoding);
data.put(SDKConstants.param_signature, strAfterSha256);
} else if (SDKConstants.SIGNMETHOD_SM3.equals(signMethod)) {
String stringData = SignUtils.parameterText(data);
String strBeforeSM3 = stringData
+ SDKConstants.AMPERSAND
+ SecureUtil.sm3X16Str(SDKConfig.getConfig().getSecureKey(), encoding);
String strAfterSM3 = SecureUtil.sm3X16Str(strBeforeSM3, encoding);
// 设置签名域值
data.put(SDKConstants.param_signature, strAfterSM3);
}
return false;
}
}

View File

@@ -14,7 +14,6 @@ import com.egzosn.pay.common.util.str.StringUtils;
import com.egzosn.pay.union.SDK.CertUtil;
import com.egzosn.pay.union.SDK.SDKConfig;
import com.egzosn.pay.union.SDK.SDKConstants;
import com.egzosn.pay.union.SDK.SDKUtils;
import com.egzosn.pay.union.enums.UnionTransactionType;
import com.egzosn.pay.union.request.UnionQueryOrder;
import org.apache.commons.logging.Log;
@@ -37,7 +36,32 @@ import java.util.Map;
public class UnionPayService extends BasePayService {
//日志
protected static final Log log = LogFactory.getLog(UnionPayService.class);
/**
* 测试域名
*/
private static final String TEST_BASE_DOMAIN = "test.95516.com";
/**
* 正式域名
*/
private static final String RELEASE_BASE_DOMAIN = "95516.com";
/**
* 交易请求地址
*/
private static final String FRONT_TRANS_URL= "https://gateway.%s/gateway/api/frontTransReq.do";
private static final String BACK_TRANS_URL= "https://gateway.%s/gateway/api/backTransReq.do";
private static final String SINGLE_QUERY_URL= "https://gateway.%s/gateway/api/queryTrans.do";
private static final String BATCH_TRANS_URL= "https://gateway.%s/gateway/api/batchTrans.do";
private static final String FILE_TRANS_URL= "https://filedownload.%s/";
private static final String APP_TRANS_URL= "https://gateway.%s/gateway/api/appTransReq.do";
private static final String CARD_TRANS_URL= "https://gateway.%s/gateway/api/cardTransReq.do";
/**
* 以下缴费产品使用,其余产品用不到
*/
// private static final String JF_FRONT_TRANS_URL= "https://gateway.%s/jiaofei/api/frontTransReq.do";
// private static final String JF_BACK_TRANS_URL= "https://gateway.%s/jiaofei/api/backTransReq.do";
// private static final String JF_SINGLE_QUERY_URL= "https://gateway.%s/jiaofei/api/queryTrans.do";
// private static final String JF_APP_TRANS_URL= "https://gateway.%s/jiaofei/api/appTransReq.do";
// private static final String JF_CARD_TRANS_URL= "https://gateway.%s/jiaofei/api/cardTransReq.do";
public UnionPayService (PayConfigStorage payConfigStorage) {
super(payConfigStorage);
@@ -77,7 +101,7 @@ public class UnionPayService extends BasePayService {
@Override
public boolean verify (Map<String, Object> result) {
if(result != null){
if(SDKUtils.validate(result, payConfigStorage.getInputCharset())){
if(this.vailSign(result)){
String respCode = result.get("respCode").toString();
if(("00").equals(respCode)){
@@ -195,16 +219,59 @@ public class UnionPayService extends BasePayService {
* @param parameters 请求参数
* @return 请求参数
*/
private Map<String, Object> setSign(Map<String, Object> parameters){
private Map<String, String> setSign(Map<String, String> parameters){
SignUtils signUtils = SignUtils.valueOf(payConfigStorage.getSignType());
String data = SignUtils.parameterText(parameters);
parameters.put(SDKConstants.param_signMethod, getSignMethod(signUtils));
String sign = createSign( SignUtils.parameterText(parameters, "&"), payConfigStorage.getInputCharset());
parameters.put("sign", sign);
String stringSign = "";
switch (signUtils){
case RSA:
parameters.put(SDKConstants.param_certId, CertUtil.getSignCertId());
stringSign = SignUtils.SHA1.createSign(data,"",payConfigStorage.getInputCharset());
stringSign = signUtils.createSign(stringSign,payConfigStorage.getKeyPrivate(),payConfigStorage.getInputCharset());
break;
case SHA256:
String before = SignUtils.SHA256.createSign(SDKConfig.getConfig().getSecureKey(),"",payConfigStorage.getInputCharset());
stringSign = SignUtils.SHA256.createSign(data,"&"+before,payConfigStorage.getInputCharset());
break;
case SM3:
stringSign = SignUtils.SM3.createSign(data,SDKConfig.getConfig().getSecureKey(),payConfigStorage.getInputCharset());
break;
default:
parameters.put(SDKConstants.param_certId, CertUtil.getSignCertId());
stringSign = SignUtils.SHA1.createSign(data,"",payConfigStorage.getInputCharset());
stringSign = signUtils.createSign(stringSign,payConfigStorage.getKeyPrivate(),payConfigStorage.getInputCharset());
}
parameters.put(SDKConstants.param_signature, stringSign);
return parameters;
}
/**
* 验证数据合法性
* @param resData 请求参数
* @return 请求参数
*/
private boolean vailSign(Map<String, Object> resData){
SignUtils signUtils = SignUtils.valueOf(payConfigStorage.getSignType());
//签名原文
String stringSign = resData.get(SDKConstants.param_signature).toString();
String data = SignUtils.parameterText(resData);
switch (signUtils){
case RSA:
//todo 不确定这样可靠
return SignUtils.RSA.verify(resData,stringSign,payConfigStorage.getKeyPublic(),payConfigStorage.getInputCharset());
case SHA256:
String before = SignUtils.SHA256.createSign(SDKConfig.getConfig().getSecureKey(),"",payConfigStorage.getInputCharset());
String nowSign = SignUtils.SHA256.createSign(data,"&"+before,payConfigStorage.getInputCharset());
return stringSign.equals(nowSign);
case SM3:
nowSign = SignUtils.SM3.createSign(data,SDKConfig.getConfig().getSecureKey(),payConfigStorage.getInputCharset());
return stringSign.equals(nowSign);
default:
return false;
}
}
/**
* 获取输出二维码,用户返回给支付端,
*
@@ -214,12 +281,9 @@ public class UnionPayService extends BasePayService {
@Override
public BufferedImage genQrPay (PayOrder order) {
Map<String ,String > params = orderInfo(order);
CertUtil.sign(params,payConfigStorage.getInputCharset().toUpperCase());
JSONObject response = getHttpRequestTemplate().postForObject(SDKConfig.getConfig().getBackRequestUrl(),params,JSONObject.class);
if(SDKUtils.validate(response,payConfigStorage.getInputCharset().toUpperCase())){
this.setSign(params);
JSONObject response = getHttpRequestTemplate().postForObject(this.getBackTransUrl(),params,JSONObject.class);
if(this.vailSign(response)){
if("00".equals(response.getString(SDKConstants.param_respCode))){
//成功,获取tn号
return MatrixToImageWriter.writeInfoToJpgBuff( response.getString(SDKConstants.param_respCode));
@@ -240,8 +304,8 @@ public class UnionPayService extends BasePayService {
@Override
public Map<String, Object> microPay (PayOrder order) {
Map<String ,String > params = orderInfo(order);
CertUtil.sign(params,payConfigStorage.getInputCharset().toUpperCase());
return getHttpRequestTemplate().postForObject(SDKConfig.getConfig().getBackRequestUrl(),params,JSONObject.class);
this.setSign(params);
return getHttpRequestTemplate().postForObject(this.getBackTransUrl(),params,JSONObject.class);
}
@@ -257,9 +321,9 @@ public class UnionPayService extends BasePayService {
Map<String ,String > params = this.getCommonParam();
UnionTransactionType.QUERY.convertMap(params);
params.put(SDKConstants.param_orderId,outTradeNo);
CertUtil.sign(params,payConfigStorage.getInputCharset().toUpperCase());
JSONObject response = getHttpRequestTemplate().postForObject(SDKConfig.getConfig().getBackRequestUrl(),params,JSONObject.class);
if(SDKUtils.validate(response,payConfigStorage.getInputCharset().toUpperCase())){
this.setSign(params);
JSONObject response = getHttpRequestTemplate().postForObject(this.getSingleQueryUrl(),params,JSONObject.class);
if(this.vailSign(response)){
if("00".equals(response.getString(SDKConstants.param_respCode))){
String origRespCode = response.getString(SDKConstants.param_origRespCode);
if(("00").equals(origRespCode)){
@@ -296,9 +360,9 @@ public class UnionPayService extends BasePayService {
if(StringUtils.isNotBlank(queryOrder.getOrigTxnTime())) {
params.put(SDKConstants.param_origTxnTime, queryOrder.getOrigOrderId());
}
CertUtil.sign(params,payConfigStorage.getInputCharset().toUpperCase());
JSONObject response = getHttpRequestTemplate().postForObject(SDKConfig.getConfig().getBackRequestUrl(),params,JSONObject.class);
if(SDKUtils.validate(response,payConfigStorage.getInputCharset().toUpperCase())){
this.setSign(params);
JSONObject response = getHttpRequestTemplate().postForObject(this.getBackTransUrl(),params,JSONObject.class);
if(this.vailSign(response)){
if("00".equals(response.getString(SDKConstants.param_respCode))){
String origRespCode = response.getString(SDKConstants.param_origRespCode);
//交易成功,更新商户订单状态
@@ -471,9 +535,9 @@ public class UnionPayService extends BasePayService {
DateFormat df = new SimpleDateFormat("MMDD");
params.put(SDKConstants.param_settleDate,df.format(new Date()));
params.put(SDKConstants.param_fileType,billType);
CertUtil.sign(params,payConfigStorage.getInputCharset().toUpperCase());
Map<String ,Object > response = getHttpRequestTemplate().postForObject(SDKConfig.getConfig().getBackRequestUrl(),params,Map.class);
if(SDKUtils.validate(response,payConfigStorage.getInputCharset().toUpperCase())){
this.setSign(params);
Map<String ,Object > response = getHttpRequestTemplate().postForObject(this.getFileTransUrl(),params,Map.class);
if(this.vailSign(response)){
if("00".equals(response.get(SDKConstants.param_respCode))){
return response.get(SDKConstants.param_fileContent).toString();
@@ -513,7 +577,51 @@ public class UnionPayService extends BasePayService {
return null;
}
// public String getFrontTransUrl () {
// return payConfigStorage.isTest() ? String.format(FRONT_TRANS_URL,TEST_BASE_DOMAIN):String.format(FRONT_TRANS_URL,RELEASE_BASE_DOMAIN);
// }
//
public String getBackTransUrl () {
return payConfigStorage.isTest() ? String.format(BACK_TRANS_URL,TEST_BASE_DOMAIN):String.format(BACK_TRANS_URL,RELEASE_BASE_DOMAIN);
}
public String getSingleQueryUrl () {
return payConfigStorage.isTest() ? String.format(SINGLE_QUERY_URL,TEST_BASE_DOMAIN):String.format(SINGLE_QUERY_URL,RELEASE_BASE_DOMAIN);
}
//
// public String getBatchTransUrl () {
// return payConfigStorage.isTest() ? String.format(BATCH_TRANS_URL,TEST_BASE_DOMAIN):String.format(BATCH_TRANS_URL,RELEASE_BASE_DOMAIN);
// }
public String getFileTransUrl () {
return payConfigStorage.isTest() ? String.format(FILE_TRANS_URL,TEST_BASE_DOMAIN):String.format(FILE_TRANS_URL,RELEASE_BASE_DOMAIN);
}
// public String getAppTransUrl () {
// return payConfigStorage.isTest() ? String.format(APP_TRANS_URL,TEST_BASE_DOMAIN):String.format(APP_TRANS_URL,RELEASE_BASE_DOMAIN);
// }
//
// public String getCardTransUrl () {
// return payConfigStorage.isTest() ? String.format(CARD_TRANS_URL,TEST_BASE_DOMAIN):String.format(CARD_TRANS_URL,RELEASE_BASE_DOMAIN);
// }
//
// public String getJfFrontTransUrl () {
// return payConfigStorage.isTest() ? String.format(JF_FRONT_TRANS_URL,TEST_BASE_DOMAIN):String.format(JF_FRONT_TRANS_URL,RELEASE_BASE_DOMAIN);
// }
//
// public String getJfBackTransUrl () {
// return payConfigStorage.isTest() ? String.format(JF_BACK_TRANS_URL,TEST_BASE_DOMAIN):String.format(JF_BACK_TRANS_URL,RELEASE_BASE_DOMAIN);
// }
//
// public String getJfSingleQueryUrl () {
// return payConfigStorage.isTest() ? String.format(JF_SINGLE_QUERY_URL,TEST_BASE_DOMAIN):String.format(JF_SINGLE_QUERY_URL,RELEASE_BASE_DOMAIN);
// }
//
// public String getJfAppTransUrl () {
// return payConfigStorage.isTest() ? String.format(JF_APP_TRANS_URL,TEST_BASE_DOMAIN):String.format(JF_APP_TRANS_URL,RELEASE_BASE_DOMAIN);
// }
//
// public String getJfCardTransUrl () {
// return payConfigStorage.isTest() ? String.format(JF_CARD_TRANS_URL,TEST_BASE_DOMAIN):String.format(JF_CARD_TRANS_URL,RELEASE_BASE_DOMAIN);
// }
}