记得上下班打卡 | git大法好,push需谨慎
Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
liquidnet-bus-v1
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
董敬伟
liquidnet-bus-v1
Commits
70db7894
Commit
70db7894
authored
Nov 08, 2021
by
anjiabin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
提交unionpay代码
parent
a3ef7eb2
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
4642 additions
and
0 deletions
+4642
-0
Acp6Service.java
...dnet/service/dragon/channel/unionpay/sdk/Acp6Service.java
+286
-0
AcpService.java
...idnet/service/dragon/channel/unionpay/sdk/AcpService.java
+837
-0
CertUtil.java
...quidnet/service/dragon/channel/unionpay/sdk/CertUtil.java
+849
-0
HttpsUtil.java
...uidnet/service/dragon/channel/unionpay/sdk/HttpsUtil.java
+281
-0
QrcService.java
...idnet/service/dragon/channel/unionpay/sdk/QrcService.java
+321
-0
SDKConfig.java
...uidnet/service/dragon/channel/unionpay/sdk/SDKConfig.java
+754
-0
SDKConstants.java
...net/service/dragon/channel/unionpay/sdk/SDKConstants.java
+401
-0
SDKUtil.java
...iquidnet/service/dragon/channel/unionpay/sdk/SDKUtil.java
+553
-0
SecureUtil.java
...idnet/service/dragon/channel/unionpay/sdk/SecureUtil.java
+312
-0
readme_and_history
...et/service/dragon/channel/unionpay/sdk/readme_and_history
+48
-0
No files found.
liquidnet-bus-service/liquidnet-service-dragon/liquidnet-service-dragon-impl/src/main/java/com/liquidnet/service/dragon/channel/unionpay/sdk/Acp6Service.java
0 → 100644
View file @
70db7894
package
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.codec.binary.Base64
;
import
java.io.IOException
;
import
java.security.PublicKey
;
import
java.util.Map
;
/**
* @ClassName Acp6Service
* @Description 全渠道6.0接口服务类,接入商户集成请可以直接参考使用本类中的方法
* @date 2020/03
*/
@Slf4j
public
class
Acp6Service
{
/**
* 请求报文签名(使用配置文件中配置的私钥证书或者对称密钥签名)<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
)
{
return
signByCertInfo
(
reqData
,
SDKConfig
.
getConfig
().
getSignCertPath
(),
SDKConfig
.
getConfig
().
getSignCertPwd
(),
encoding
);
}
/**
* 多证书签名(通过传入私钥证书路径和密码签名)<br>
* 功能:如果有多个商户号接入银联,每个商户号对应不同的证书可以使用此方法:传入私钥证书和密码(并且在acp_sdk.properties中 配置 acpsdk.singleMode=false)<br>
* @param reqData 请求报文map<br>
* @param certPath 签名私钥文件(带路径)<br>
* @param certPwd 签名私钥密码<br>
* @param encoding 上送请求报文域encoding字段的值<br>
* @return 签名后的map对象<br>
*/
public
static
Map
<
String
,
String
>
signByCertInfo
(
Map
<
String
,
String
>
reqData
,
String
certPath
,
String
certPwd
,
String
encoding
)
{
Map
<
String
,
String
>
data
=
SDKUtil
.
filterBlank
(
reqData
);
if
(
SDKUtil
.
isEmpty
(
encoding
))
{
encoding
=
"UTF-8"
;
}
if
(
SDKUtil
.
isEmpty
(
certPath
)
||
SDKUtil
.
isEmpty
(
certPwd
))
{
log
.
error
(
"CertPath or CertPwd is empty"
);
return
data
;
}
try
{
data
.
put
(
SDKConstants
.
param_certId
,
CertUtil
.
getCertIdByKeyStoreMap
(
certPath
,
certPwd
));
data
.
put
(
SDKConstants
.
param_signature
,
SDKUtil
.
signRsa2
(
data
,
certPath
,
certPwd
,
encoding
));
return
data
;
}
catch
(
Exception
e
)
{
log
.
error
(
"Sign Error"
,
e
);
return
data
;
}
}
/**
* 验证签名<br>
* @param data 返回报文数据<br>
* @param encoding 上送请求报文域encoding字段的值<br>
* @return true 通过 false 未通过<br>
*/
public
static
boolean
validate
(
Map
<
String
,
String
>
data
,
String
encoding
)
{
log
.
info
(
"验签处理开始"
);
if
(
SDKUtil
.
isEmpty
(
encoding
))
{
encoding
=
"UTF-8"
;
}
String
certId
=
data
.
get
(
SDKConstants
.
param_certId
);
log
.
info
(
"对返回报文串验签使用的验签公钥序列号:["
+
certId
+
"]"
);
PublicKey
verifyKey
=
CertUtil
.
getValidatePublicKey
(
certId
);
if
(
verifyKey
==
null
)
{
log
.
error
(
"未找到此序列号证书。"
);
return
false
;
}
try
{
boolean
result
=
SDKUtil
.
verifyRsa2
(
data
,
verifyKey
,
encoding
);
log
.
info
(
"验签"
+
(
result
?
"成功"
:
"失败"
)
+
"。"
);
return
result
;
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
return
false
;
}
}
/**
* 获取应答报文中的加密公钥证书,并存储到本地,备份原始证书,并自动替换证书<br>
* 更新成功则返回1,无更新返回0,失败异常返回-1<br>
* @return
*/
public
static
int
updateEncryptCert
(
String
strCert
,
String
certType
)
{
return
SDKUtil
.
updateEncryptCert
(
strCert
,
certType
);
}
/**
* 密码加密并做base64<br>
* @param accNo 卡号<br>
* @param pin 密码<br>
* @param encoding<br>
* @return 加密的内容<br>
*/
public
static
String
encryptPin
(
String
accNo
,
String
pin
,
String
encoding
)
{
byte
[]
pinblock
=
SecureUtil
.
pinblock
(
accNo
,
pin
);
return
Base64
.
encodeBase64String
(
SecureUtil
.
encrypt
(
CertUtil
.
getPinEncryptCert
().
pubKey
,
pinblock
));
}
// /**
// * 密码加密并做base64<br>
// * @param accNo 卡号<br>
// * @param pin 密码<br>
// * @param encoding<br>
// * @return 加密的内容<br>
// */
// public static String encryptPin(String pin, String encoding) {
// byte[] pinblock = SecureUtil.pinblock(pin);
// return Base64.encodeBase64String(SecureUtil.encrypt(CertUtil.getPinEncryptCert().pubKey, pinblock));
// }
/**
* 敏感信息加密并做base64(卡号,手机号,cvn2,有效期)<br>
* @param data 送 phoneNo,cvn2,有效期<br>
* @param encoding<br>
* @return 加密的密文<br>
*/
public
static
String
encryptData
(
String
data
,
String
encoding
)
{
return
AcpService
.
encryptData
(
data
,
encoding
);
}
/**
* @param data 明文<br>
* @return 加密的密文<br>
*/
public
static
String
encryptData
(
byte
[]
data
)
{
try
{
return
Base64
.
encodeBase64String
(
SecureUtil
.
encrypt
(
CertUtil
.
getEncryptCert
().
pubKey
,
data
));
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
return
null
;
}
}
/**
* @param data 明文<br>
* @return 加密的密文<br>
*/
public
static
String
tripleDesEncryptECBPKCS5Padding
(
byte
[]
key
,
byte
[]
data
)
{
try
{
return
Base64
.
encodeBase64String
(
SecureUtil
.
tripleDesEncryptECBPKCS5Padding
(
key
,
SecureUtil
.
rightPadZero
(
data
,
8
)));
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
return
null
;
}
}
/**
* 敏感信息解密,使用配置文件acp_sdk.properties解密<br>
* @param base64EncryptedInfo 加密信息<br>
* @param encoding<br>
* @return 解密后的明文<br>
*/
public
static
String
decryptData
(
String
base64EncryptedInfo
,
String
encoding
)
{
return
AcpService
.
decryptData
(
base64EncryptedInfo
,
encoding
);
}
/**
* 敏感信息解密,通过传入的私钥解密<br>
* @param base64EncryptedInfo 加密信息<br>
* @param certPath 私钥文件(带全路径)<br>
* @param certPwd 私钥密码<br>
* @param encoding<br>
* @return
*/
public
static
String
decryptData
(
String
base64EncryptedInfo
,
String
certPath
,
String
certPwd
,
String
encoding
)
{
return
AcpService
.
decryptData
(
base64EncryptedInfo
,
certPath
,
certPwd
,
encoding
);
}
/**
* 获取敏感信息加密证书的物理序列号<br>
* @return
*/
public
static
String
getEncryptCertId
(){
return
CertUtil
.
getEncryptCert
().
certId
;
}
/**
* 获取敏感信息加密证书的物理序列号<br>
* @return
*/
public
static
String
getPinEncryptCertId
(){
return
CertUtil
.
getPinEncryptCert
().
certId
;
}
/**
* 功能:后台交易提交请求报文并接收同步应答报文<br>
* @param reqData 请求报文<br>
* @param reqUrl 请求地址<br>
* @param encoding<br>
* @return 应答http 200返回true ,其他false<br>
*/
public
static
Map
<
String
,
String
>
post
(
Map
<
String
,
String
>
reqData
,
String
reqUrl
,
String
encoding
)
{
if
(
reqData
==
null
||
reqUrl
==
null
)
{
log
.
error
(
"null input"
);
return
null
;
}
log
.
info
(
"请求银联地址:"
+
reqUrl
+
",请求参数:"
+
reqData
.
toString
());
if
(
reqUrl
.
startsWith
(
"https://"
)
&&
!
SDKConfig
.
getConfig
().
isIfValidateRemoteCert
())
{
reqUrl
=
"u"
+
reqUrl
;
}
try
{
byte
[]
respBytes
=
HttpsUtil
.
post
(
reqUrl
,
SDKUtil
.
createLinkString
(
reqData
,
false
,
true
,
encoding
).
getBytes
(
encoding
));
if
(
respBytes
==
null
)
{
log
.
error
(
"post失败"
);
return
null
;
}
Map
<
String
,
String
>
result
=
SDKUtil
.
parseQString
(
new
String
(
respBytes
,
encoding
),
encoding
);
log
.
info
(
"应答参数:"
+
result
);
return
result
;
}
catch
(
Exception
e
)
{
log
.
error
(
"post失败:"
+
e
.
getMessage
(),
e
);
return
null
;
}
}
/**
* 功能:后台交易提交请求报文并接收同步应答报文<br>
* @param reqData 请求报文<br>
* @param reqUrl 请求地址<br>
* @param encoding<br>
* @return 应答http 200返回true ,其他false<br>
*/
public
static
String
postNotice
(
Map
<
String
,
String
>
reqData
,
String
reqUrl
,
String
encoding
)
{
if
(
reqData
==
null
||
reqUrl
==
null
)
{
log
.
error
(
"null input"
);
return
null
;
}
log
.
info
(
"请求银联地址:"
+
reqUrl
+
",请求参数:"
+
reqData
.
toString
());
if
(
reqUrl
.
startsWith
(
"https://"
)
&&
!
SDKConfig
.
getConfig
().
isIfValidateRemoteCert
())
{
reqUrl
=
"u"
+
reqUrl
;
}
try
{
byte
[]
respBytes
=
HttpsUtil
.
post
(
reqUrl
,
SDKUtil
.
createLinkString
(
reqData
,
false
,
true
,
encoding
).
getBytes
(
encoding
));
if
(
respBytes
==
null
)
{
log
.
error
(
"post失败"
);
return
null
;
}
String
result
=
new
String
(
respBytes
,
encoding
);
log
.
info
(
"应答体:"
+
result
);
return
result
;
}
catch
(
Exception
e
)
{
log
.
error
(
"post失败:"
+
e
.
getMessage
(),
e
);
return
null
;
}
}
/**
* 对字符串做base64<br>
* @param rawStr<br>
* @param encoding<br>
* @return<br>
* @throws IOException
*/
public
static
String
base64Encode
(
String
rawStr
,
String
encoding
){
return
AcpService
.
base64Encode
(
rawStr
,
encoding
);
}
/**
* 对字符串做base64<br>
* @param base64Str<br>
* @param encoding<br>
* @return<br>
* @throws IOException
*/
public
static
String
base64Decode
(
String
base64Str
,
String
encoding
){
return
AcpService
.
base64Decode
(
base64Str
,
encoding
);
}
}
liquidnet-bus-service/liquidnet-service-dragon/liquidnet-service-dragon-impl/src/main/java/com/liquidnet/service/dragon/channel/unionpay/sdk/AcpService.java
0 → 100644
View file @
70db7894
package
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.codec.binary.Base64
;
import
java.io.*
;
import
java.nio.charset.Charset
;
import
java.security.PublicKey
;
import
java.util.Iterator
;
import
java.util.Map
;
import
java.util.Map.Entry
;
import
java.util.Set
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
import
static
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
SDKConstants
.*;
/**
* @ClassName AcpService
* @Description acpsdk接口服务类,接入商户集成请可以直接参考使用本类中的方法
* @date 2016-7-22 下午2:44:37
*/
@Slf4j
public
class
AcpService
{
/**
* 请求报文签名(使用配置文件中配置的私钥证书或者对称密钥签名)<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
)
{
Map
<
String
,
String
>
data
=
SDKUtil
.
filterBlank
(
reqData
);
if
(
SDKUtil
.
isEmpty
(
encoding
))
{
encoding
=
"UTF-8"
;
}
String
signMethod
=
data
.
get
(
param_signMethod
);
String
version
=
data
.
get
(
param_version
);
if
(
SDKUtil
.
isEmpty
(
signMethod
))
{
signMethod
=
SIGNMETHOD_RSA
;
}
try
{
if
(
SIGNMETHOD_RSA
.
equals
(
signMethod
))
{
return
signByCertInfo
(
data
,
SDKConfig
.
getConfig
().
getSignCertPath
(),
SDKConfig
.
getConfig
().
getSignCertPwd
(),
encoding
);
}
else
if
(
SIGNMETHOD_SHA256
.
equals
(
signMethod
))
{
return
signBySecureKey
(
data
,
SDKConfig
.
getConfig
().
getSecureKey
(),
encoding
);
}
else
if
(
SIGNMETHOD_SM3
.
equals
(
signMethod
))
{
return
signBySecureKey
(
data
,
SDKConfig
.
getConfig
().
getSecureKey
(),
encoding
);
}
log
.
error
(
"未实现签名方法, version="
+
version
+
", signMethod="
+
signMethod
);
return
data
;
}
catch
(
Exception
e
)
{
log
.
error
(
"Sign Error"
,
e
);
return
data
;
}
}
/**
* 多证书签名(通过传入私钥证书路径和密码签名)<br>
* 功能:如果有多个商户号接入银联,每个商户号对应不同的证书可以使用此方法:传入私钥证书和密码(并且在acp_sdk.properties中 配置 acpsdk.singleMode=false)<br>
* @param reqData 请求报文map<br>
* @param certPath 签名私钥文件(带路径)<br>
* @param certPwd 签名私钥密码<br>
* @param encoding 上送请求报文域encoding字段的值<br>
* @return 签名后的map对象<br>
*/
public
static
Map
<
String
,
String
>
signByCertInfo
(
Map
<
String
,
String
>
reqData
,
String
certPath
,
String
certPwd
,
String
encoding
)
{
Map
<
String
,
String
>
data
=
SDKUtil
.
filterBlank
(
reqData
);
if
(
SDKUtil
.
isEmpty
(
encoding
))
{
encoding
=
"UTF-8"
;
}
if
(
SDKUtil
.
isEmpty
(
certPath
)
||
SDKUtil
.
isEmpty
(
certPwd
))
{
log
.
error
(
"CertPath or CertPwd is empty"
);
return
data
;
}
String
signMethod
=
data
.
get
(
param_signMethod
);
if
(
SDKUtil
.
isEmpty
(
signMethod
))
{
signMethod
=
SIGNMETHOD_RSA
;
}
String
version
=
data
.
get
(
SDKConstants
.
param_version
);
try
{
if
(
VERSION_5_0_1
.
equals
(
version
)
||
VERSION_5_0_0
.
equals
(
version
)){
if
(
SIGNMETHOD_RSA
.
equals
(
signMethod
))
{
data
.
put
(
SDKConstants
.
param_certId
,
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
CertUtil
.
getCertIdByKeyStoreMap
(
certPath
,
certPwd
));
data
.
put
(
SDKConstants
.
param_signature
,
SDKUtil
.
signRsa
(
data
,
certPath
,
certPwd
,
encoding
));
return
data
;
}
}
else
if
(
VERSION_5_1_0
.
equals
(
version
)){
if
(
SIGNMETHOD_RSA
.
equals
(
signMethod
))
{
data
.
put
(
SDKConstants
.
param_certId
,
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
CertUtil
.
getCertIdByKeyStoreMap
(
certPath
,
certPwd
));
data
.
put
(
SDKConstants
.
param_signature
,
SDKUtil
.
signRsa2
(
data
,
certPath
,
certPwd
,
encoding
));
return
data
;
}
}
log
.
error
(
"未实现签名方法, version="
+
version
+
", signMethod="
+
signMethod
);
return
data
;
}
catch
(
Exception
e
)
{
log
.
error
(
"Sign Error"
,
e
);
return
data
;
}
}
/**
* 多密钥签名(通过传入密钥签名)<br>
* 功能:如果有多个商户号接入银联,每个商户号对应不同的证书可以使用此方法:传入私钥证书和密码(并且在acp_sdk.properties中 配置 acpsdk.singleMode=false)<br>
* @param reqData 请求报文map<br>
* @param secureKey 签名对称密钥<br>
* @param encoding 上送请求报文域encoding字段的值<br>
* @return 签名后的map对象<br>
*/
public
static
Map
<
String
,
String
>
signBySecureKey
(
Map
<
String
,
String
>
reqData
,
String
secureKey
,
String
encoding
)
{
Map
<
String
,
String
>
data
=
SDKUtil
.
filterBlank
(
reqData
);
if
(
SDKUtil
.
isEmpty
(
encoding
))
{
encoding
=
"UTF-8"
;
}
if
(
SDKUtil
.
isEmpty
(
secureKey
))
{
log
.
error
(
"secureKey is empty"
);
return
data
;
}
String
signMethod
=
data
.
get
(
param_signMethod
);
String
version
=
data
.
get
(
param_version
);
try
{
if
(
VERSION_5_1_0
.
equals
(
version
)){
if
(
SIGNMETHOD_SHA256
.
equals
(
signMethod
))
{
data
.
put
(
SDKConstants
.
param_signature
,
SDKUtil
.
signSha256
(
data
,
secureKey
,
encoding
));
return
data
;
}
else
if
(
SIGNMETHOD_SM3
.
equals
(
signMethod
))
{
data
.
put
(
SDKConstants
.
param_signature
,
SDKUtil
.
signSm3
(
data
,
secureKey
,
encoding
));
return
data
;
}
}
log
.
error
(
"未实现签名方法, version="
+
version
+
", signMethod="
+
signMethod
);
return
data
;
}
catch
(
Exception
e
)
{
log
.
error
(
"Sign Error"
,
e
);
return
data
;
}
}
/**
* 验证签名(SHA-1摘要算法)<br>
* @param data 返回报文数据<br>
* @param encoding 上送请求报文域encoding字段的值<br>
* @return true 通过 false 未通过<br>
*/
public
static
boolean
validate
(
Map
<
String
,
String
>
data
,
String
encoding
)
{
log
.
info
(
"验签处理开始"
);
if
(
SDKUtil
.
isEmpty
(
encoding
))
{
encoding
=
"UTF-8"
;
}
String
signMethod
=
data
.
get
(
SDKConstants
.
param_signMethod
);
if
(
SDKUtil
.
isEmpty
(
signMethod
))
{
signMethod
=
SIGNMETHOD_RSA
;
}
String
version
=
data
.
get
(
SDKConstants
.
param_version
);
try
{
if
(
VERSION_5_1_0
.
equals
(
version
)){
if
(
SIGNMETHOD_SHA256
.
equals
(
signMethod
))
return
SDKUtil
.
verifySha256
(
data
,
SDKConfig
.
getConfig
().
getSecureKey
(),
encoding
);
else
if
(
SIGNMETHOD_SM3
.
equals
(
signMethod
))
return
SDKUtil
.
verifySm3
(
data
,
SDKConfig
.
getConfig
().
getSecureKey
(),
encoding
);
}
if
(
SIGNMETHOD_RSA
.
equals
(
signMethod
))
{
String
strCert
=
data
.
get
(
SDKConstants
.
param_signPubKeyCert
);
String
certId
=
data
.
get
(
SDKConstants
.
param_certId
);
PublicKey
verifyKey
=
null
;
if
(!
SDKUtil
.
isEmpty
(
strCert
))
verifyKey
=
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
CertUtil
.
verifyAndGetVerifyPubKey
(
strCert
);
else
if
(!
SDKUtil
.
isEmpty
(
certId
)){
log
.
info
(
"对返回报文串验签使用的验签公钥序列号:["
+
certId
+
"]"
);
verifyKey
=
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
CertUtil
.
getValidatePublicKey
(
certId
);
}
if
(
verifyKey
==
null
)
{
log
.
error
(
"未成功获取验签公钥,验签失败。"
);
return
false
;
}
if
(
VERSION_5_0_0
.
equals
(
version
)
||
VERSION_5_0_1
.
equals
(
version
)
)
{
boolean
result
=
SDKUtil
.
verifyRsa
(
data
,
verifyKey
,
encoding
);
log
.
info
(
"验签"
+
(
result
?
"成功"
:
"失败"
)
+
"。"
);
return
result
;
}
else
if
(
VERSION_5_1_0
.
equals
(
version
))
{
boolean
result
=
SDKUtil
.
verifyRsa2
(
data
,
verifyKey
,
encoding
);
log
.
info
(
"验签"
+
(
result
?
"成功"
:
"失败"
)
+
"。"
);
return
result
;
}
}
log
.
error
(
"无法判断验签方法,验签失败。version="
+
version
+
", signMethod="
+
signMethod
);
return
false
;
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
return
false
;
}
}
/**
* 多密钥验签(通过传入密钥签名)<br>
* @param data 返回报文数据<br>
* @param secureKey 密钥<br>
* @param encoding 上送请求报文域encoding字段的值<br>
* @return true 通过 false 未通过<br>
*/
public
static
boolean
validateBySecureKey
(
Map
<
String
,
String
>
data
,
String
secureKey
,
String
encoding
)
{
if
(
secureKey
==
null
||
""
.
equals
(
secureKey
))
{
log
.
error
(
"secureKey为空,验签失败。"
);
return
false
;
}
log
.
info
(
"验签处理开始"
);
if
(
SDKUtil
.
isEmpty
(
encoding
))
{
encoding
=
"UTF-8"
;
}
String
signMethod
=
data
.
get
(
SDKConstants
.
param_signMethod
);
String
version
=
data
.
get
(
SDKConstants
.
param_version
);
try
{
if
(
VERSION_5_1_0
.
equals
(
version
)){
if
(
SIGNMETHOD_SHA256
.
equals
(
signMethod
))
{
boolean
result
=
SDKUtil
.
verifySha256
(
data
,
secureKey
,
encoding
);
log
.
info
(
"验签"
+
(
result
?
"成功"
:
"失败"
)
+
"。"
);
return
result
;
}
else
if
(
SIGNMETHOD_SM3
.
equals
(
signMethod
))
{
boolean
result
=
SDKUtil
.
verifySm3
(
data
,
secureKey
,
encoding
);
log
.
info
(
"验签"
+
(
result
?
"成功"
:
"失败"
)
+
"。"
);
return
result
;
}
}
log
.
error
(
"无法判断验签方法,验签失败。version="
+
version
+
", signMethod="
+
signMethod
);
return
false
;
}
catch
(
Exception
e
)
{
log
.
error
(
"validateBySecureKey Error"
,
e
);
return
false
;
}
}
/**
* @deprecated 5.1.0开发包已删除此方法,请直接参考5.1.0开发包中的VerifyAppData.java验签。
* 对控件支付成功返回的结果信息中data域进行验签(控件端获取的应答信息)<br>
* @param jsonData json格式数据,例如:{"sign" : "J6rPLClQ64szrdXCOtV1ccOMzUmpiOKllp9cseBuRqJ71pBKPPkZ1FallzW18gyP7CvKh1RxfNNJ66AyXNMFJi1OSOsteAAFjF5GZp0Xsfm3LeHaN3j/N7p86k3B1GrSPvSnSw1LqnYuIBmebBkC1OD0Qi7qaYUJosyA1E8Ld8oGRZT5RR2gLGBoiAVraDiz9sci5zwQcLtmfpT5KFk/eTy4+W9SsC0M/2sVj43R9ePENlEvF8UpmZBqakyg5FO8+JMBz3kZ4fwnutI5pWPdYIWdVrloBpOa+N4pzhVRKD4eWJ0CoiD+joMS7+C0aPIEymYFLBNYQCjM0KV7N726LA==", "data" : "pay_result=success&tn=201602141008032671528&cert_id=68759585097"}
* @return 是否成功
*/
public
static
boolean
validateAppResponse
(
String
jsonData
,
String
encoding
)
{
log
.
info
(
"控件应答信息验签处理开始:["
+
jsonData
+
"]"
);
if
(
SDKUtil
.
isEmpty
(
encoding
))
{
encoding
=
"UTF-8"
;
}
Pattern
p
=
Pattern
.
compile
(
"\\s*\"sign\"\\s*:\\s*\"([^\"]*)\"\\s*"
);
Matcher
m
=
p
.
matcher
(
jsonData
);
if
(!
m
.
find
())
return
false
;
String
sign
=
m
.
group
(
1
);
p
=
Pattern
.
compile
(
"\\s*\"data\"\\s*:\\s*\"([^\"]*)\"\\s*"
);
m
=
p
.
matcher
(
jsonData
);
if
(!
m
.
find
())
return
false
;
String
data
=
m
.
group
(
1
);
p
=
Pattern
.
compile
(
"cert_id=(\\d*)"
);
m
=
p
.
matcher
(
jsonData
);
if
(!
m
.
find
())
return
false
;
String
certId
=
m
.
group
(
1
);
try
{
// 验证签名需要用银联发给商户的公钥证书.
return
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
SecureUtil
.
verifySignature
(
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
CertUtil
.
getValidatePublicKey
(
certId
),
Base64
.
decodeBase64
(
sign
),
SDKUtil
.
byteArrayToHexString
(
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
SecureUtil
.
sha1
(
data
.
getBytes
(
encoding
))).
getBytes
(
encoding
));
}
catch
(
UnsupportedEncodingException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
return
false
;
}
/**
* 功能:后台交易提交请求报文并接收同步应答报文<br>
* @param reqData 请求报文<br>
* @param reqUrl 请求地址<br>
* @param encoding<br>
* @return 应答http 200返回true ,其他false<br>
*/
public
static
Map
<
String
,
String
>
post
(
Map
<
String
,
String
>
reqData
,
String
reqUrl
,
String
encoding
)
{
if
(
reqData
==
null
||
reqUrl
==
null
)
{
log
.
error
(
"post err: null input"
);
return
null
;
}
log
.
info
(
"请求银联地址:"
+
reqUrl
+
",请求参数:"
+
reqData
.
toString
());
if
(
reqUrl
.
startsWith
(
"https://"
)
&&
!
SDKConfig
.
getConfig
().
isIfValidateRemoteCert
())
{
reqUrl
=
"u"
+
reqUrl
;
}
try
{
byte
[]
respBytes
=
HttpsUtil
.
post
(
reqUrl
,
SDKUtil
.
createLinkString
(
reqData
,
false
,
true
,
encoding
).
getBytes
(
encoding
));
if
(
respBytes
==
null
)
{
log
.
error
(
"post失败"
);
return
null
;
}
Map
<
String
,
String
>
result
=
SDKUtil
.
parseRespString
(
new
String
(
respBytes
,
encoding
));
log
.
info
(
"应答参数:"
+
result
);
return
result
;
}
catch
(
Exception
e
)
{
log
.
error
(
"post失败:"
+
e
.
getMessage
(),
e
);
return
null
;
}
}
/**
* 功能:http Get方法 便民缴费产品中使用<br>
* @param reqUrl 请求地址<br>
* @param encoding<br>
* @return
*/
public
static
String
get
(
String
reqUrl
,
String
encoding
)
{
if
(
reqUrl
==
null
)
{
log
.
error
(
"null input"
);
return
null
;
}
log
.
info
(
"get请求银联地址:"
+
reqUrl
);
if
(!
SDKConfig
.
getConfig
().
isIfValidateRemoteCert
())
{
reqUrl
=
"u"
+
reqUrl
;
}
try
{
byte
[]
respBytes
=
HttpsUtil
.
get
(
reqUrl
);
if
(
respBytes
==
null
)
{
log
.
error
(
"post失败"
);
return
null
;
}
String
result
=
new
String
(
respBytes
,
encoding
);
log
.
info
(
"应答:"
+
result
);
return
result
;
}
catch
(
Exception
e
)
{
log
.
error
(
"post失败:"
+
e
.
getMessage
(),
e
);
return
null
;
}
}
/**
* 功能:前台交易构造HTTP POST自动提交表单<br>
* @param reqUrl 表单提交地址<br>
* @param hiddens 以MAP形式存储的表单键值<br>
* @param encoding 上送请求报文域encoding字段的值<br>
* @return 构造好的HTTP POST交易表单<br>
*/
public
static
String
createAutoFormHtml
(
String
reqUrl
,
Map
<
String
,
String
>
hiddens
,
String
encoding
)
{
StringBuffer
sf
=
new
StringBuffer
();
sf
.
append
(
"<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset="
+
encoding
+
"\"/></head><body>"
);
sf
.
append
(
"<form id = \"pay_form\" action=\""
+
reqUrl
+
"\" method=\"post\">"
);
if
(
null
!=
hiddens
&&
0
!=
hiddens
.
size
())
{
Set
<
Entry
<
String
,
String
>>
set
=
hiddens
.
entrySet
();
Iterator
<
Entry
<
String
,
String
>>
it
=
set
.
iterator
();
while
(
it
.
hasNext
())
{
Entry
<
String
,
String
>
ey
=
it
.
next
();
String
key
=
ey
.
getKey
();
String
value
=
ey
.
getValue
();
sf
.
append
(
"<input type=\"hidden\" name=\""
+
key
+
"\" id=\""
+
key
+
"\" value=\""
+
value
+
"\"/>"
);
}
}
sf
.
append
(
"</form>"
);
sf
.
append
(
"</body>"
);
sf
.
append
(
"<script type=\"text/javascript\">"
);
sf
.
append
(
"document.all.pay_form.submit();"
);
sf
.
append
(
"</script>"
);
sf
.
append
(
"</html>"
);
String
html
=
sf
.
toString
();
log
.
info
(
"打印请求HTML,此为请求报文,为联调排查问题的依据:"
+
html
);
return
html
;
}
/**
* 功能:将批量文件内容使用DEFLATE压缩算法压缩,Base64编码生成字符串并返回<br>
* 适用到的交易:批量代付,批量代收,批量退货<br>
* @param filePath 批量文件-全路径文件名<br>
* @return
*/
public
static
String
enCodeFileContent
(
String
filePath
,
String
encoding
){
String
baseFileContent
=
""
;
File
file
=
new
File
(
filePath
);
if
(!
file
.
exists
())
{
try
{
file
.
createNewFile
();
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
}
InputStream
in
=
null
;
try
{
in
=
new
FileInputStream
(
file
);
int
fl
=
in
.
available
();
if
(
null
!=
in
)
{
byte
[]
s
=
new
byte
[
fl
];
in
.
read
(
s
,
0
,
fl
);
// 压缩编码.
baseFileContent
=
Base64
.
encodeBase64String
(
SDKUtil
.
deflater
(
s
));
}
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
finally
{
if
(
null
!=
in
)
{
try
{
in
.
close
();
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
}
}
return
baseFileContent
;
}
/**
* 功能:解析交易返回的fileContent字符串并落地 ( 解base64,解DEFLATE压缩并落地)<br>
* 适用到的交易:对账文件下载,批量交易状态查询<br>
* @param data 返回报文map<br>
* @param fileDirectory 落地的文件目录(绝对路径)
* @param encoding 上送请求报文域encoding字段的值<br>
*/
public
static
String
deCodeFileContent
(
Map
<
String
,
String
>
data
,
String
fileDirectory
,
String
encoding
)
{
// 解析返回文件
String
filePath
=
null
;
String
fileContent
=
data
.
get
(
SDKConstants
.
param_fileContent
);
if
(
null
!=
fileContent
&&
!
""
.
equals
(
fileContent
))
{
FileOutputStream
out
=
null
;
try
{
byte
[]
fileArray
=
SDKUtil
.
inflater
(
Base64
.
decodeBase64
(
fileContent
));
if
(
SDKUtil
.
isEmpty
(
data
.
get
(
"fileName"
)))
{
filePath
=
fileDirectory
+
File
.
separator
+
data
.
get
(
"merId"
)
+
"_"
+
data
.
get
(
"batchNo"
)
+
"_"
+
data
.
get
(
"txnTime"
)
+
".txt"
;
}
else
{
filePath
=
fileDirectory
+
File
.
separator
+
data
.
get
(
"fileName"
);
}
File
file
=
new
File
(
filePath
);
if
(
file
.
exists
())
{
file
.
delete
();
}
file
.
createNewFile
();
out
=
new
FileOutputStream
(
file
);
out
.
write
(
fileArray
,
0
,
fileArray
.
length
);
out
.
flush
();
}
catch
(
UnsupportedEncodingException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
finally
{
try
{
out
.
close
();
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
}
}
return
filePath
;
}
/**
* 功能:将结果文件内容 转换成明文字符串:解base64,解压缩<br>
* 适用到的交易:批量交易状态查询<br>
* @param fileContent 批量交易状态查询返回的文件内容<br>
* @return 内容明文<br>
*/
public
static
String
getFileContent
(
String
fileContent
,
String
encoding
){
String
fc
=
""
;
try
{
fc
=
new
String
(
SDKUtil
.
inflater
(
Base64
.
decodeBase64
(
fileContent
)),
encoding
);
}
catch
(
UnsupportedEncodingException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
return
fc
;
}
/**
* 功能:持卡人信息域customerInfo构造<br>
* 说明:不勾选对敏感信息加密权限使用旧的构造customerInfo域方式,不对敏感信息进行加密(对 phoneNo,cvn2, expired不加密),但如果送pin的话则加密<br>
* @param customerInfoMap 信息域请求参数 key送域名value送值,必送<br>
* 例如:customerInfoMap.put("certifTp", "01"); //证件类型<br>
customerInfoMap.put("certifId", "341126197709218366"); //证件号码<br>
customerInfoMap.put("customerNm", "互联网"); //姓名<br>
customerInfoMap.put("phoneNo", "13552535506"); //手机号<br>
customerInfoMap.put("smsCode", "123456"); //短信验证码<br>
customerInfoMap.put("pin", "111111"); //密码(加密)<br>
customerInfoMap.put("cvn2", "123"); //卡背面的cvn2三位数字(不加密)<br>
customerInfoMap.put("expired", "2311"); //有效期 年在前月在后(不加密)<br>
* @param accNo customerInfoMap送了密码那么卡号必送,如果customerInfoMap未送密码pin,此字段可以不送<br>
* @param encoding 上送请求报文域encoding字段的值<br>
* @return base64后的持卡人信息域字段<br>
*/
public
static
String
getCustomerInfo
(
Map
<
String
,
String
>
customerInfoMap
,
String
accNo
,
String
encoding
)
{
if
(
customerInfoMap
.
isEmpty
())
return
"{}"
;
StringBuffer
sf
=
new
StringBuffer
(
"{"
);
for
(
Iterator
<
String
>
it
=
customerInfoMap
.
keySet
().
iterator
();
it
.
hasNext
();){
String
key
=
it
.
next
();
String
value
=
customerInfoMap
.
get
(
key
);
if
(
key
.
equals
(
"pin"
)){
if
(
null
==
accNo
||
""
.
equals
(
accNo
.
trim
())){
log
.
info
(
"送了密码(PIN),必须在getCustomerInfo参数中上传卡号"
);
throw
new
RuntimeException
(
"加密PIN没送卡号无法后续处理"
);
}
else
{
value
=
encryptPin
(
accNo
,
value
,
encoding
);
}
}
sf
.
append
(
key
).
append
(
SDKConstants
.
EQUAL
).
append
(
value
);
if
(
it
.
hasNext
())
sf
.
append
(
SDKConstants
.
AMPERSAND
);
}
String
customerInfo
=
sf
.
append
(
"}"
).
toString
();
log
.
info
(
"组装的customerInfo明文:"
+
customerInfo
);
try
{
return
Base64
.
encodeBase64String
(
sf
.
toString
().
getBytes
(
encoding
));
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
return
customerInfo
;
}
/**
* 功能:持卡人信息域customerInfo构造,勾选对敏感信息加密权限 适用新加密规范,对pin和phoneNo,cvn2,expired加密 <br>
* 适用到的交易: <br>
* @param customerInfoMap 信息域请求参数 key送域名value送值,必送 <br>
* 例如:customerInfoMap.put("certifTp", "01"); //证件类型 <br>
customerInfoMap.put("certifId", "341126197709218366"); //证件号码 <br>
customerInfoMap.put("customerNm", "互联网"); //姓名 <br>
customerInfoMap.put("smsCode", "123456"); //短信验证码 <br>
customerInfoMap.put("pin", "111111"); //密码(加密) <br>
customerInfoMap.put("phoneNo", "13552535506"); //手机号(加密) <br>
customerInfoMap.put("cvn2", "123"); //卡背面的cvn2三位数字(加密) <br>
customerInfoMap.put("expired", "2311"); //有效期 年在前月在后(加密) <br>
* @param accNo customerInfoMap送了密码那么卡号必送,如果customerInfoMap未送密码PIN,此字段可以不送<br>
* @param encoding 上送请求报文域encoding字段的值
* @return base64后的持卡人信息域字段 <br>
*/
public
static
String
getCustomerInfoWithEncrypt
(
Map
<
String
,
String
>
customerInfoMap
,
String
accNo
,
String
encoding
)
{
if
(
customerInfoMap
.
isEmpty
())
return
"{}"
;
StringBuffer
sf
=
new
StringBuffer
(
"{"
);
//敏感信息加密域
StringBuffer
encryptedInfoSb
=
new
StringBuffer
(
""
);
for
(
Iterator
<
String
>
it
=
customerInfoMap
.
keySet
().
iterator
();
it
.
hasNext
();){
String
key
=
it
.
next
();
String
value
=
customerInfoMap
.
get
(
key
);
if
(
key
.
equals
(
"phoneNo"
)
||
key
.
equals
(
"cvn2"
)
||
key
.
equals
(
"expired"
)){
encryptedInfoSb
.
append
(
key
).
append
(
SDKConstants
.
EQUAL
).
append
(
value
).
append
(
SDKConstants
.
AMPERSAND
);
}
else
{
if
(
key
.
equals
(
"pin"
)){
if
(
null
==
accNo
||
""
.
equals
(
accNo
.
trim
())){
log
.
info
(
"送了密码(PIN),必须在getCustomerInfoWithEncrypt参数中上传卡号"
);
throw
new
RuntimeException
(
"加密PIN没送卡号无法后续处理"
);
}
else
{
value
=
encryptPin
(
accNo
,
value
,
encoding
);
}
}
sf
.
append
(
key
).
append
(
SDKConstants
.
EQUAL
).
append
(
value
).
append
(
SDKConstants
.
AMPERSAND
);
}
}
if
(!
encryptedInfoSb
.
toString
().
equals
(
""
)){
encryptedInfoSb
.
setLength
(
encryptedInfoSb
.
length
()-
1
);
//去掉最后一个&符号
log
.
info
(
"组装的customerInfo encryptedInfo明文:"
+
encryptedInfoSb
.
toString
());
sf
.
append
(
"encryptedInfo"
).
append
(
SDKConstants
.
EQUAL
).
append
(
encryptData
(
encryptedInfoSb
.
toString
(),
encoding
));
}
else
{
sf
.
setLength
(
sf
.
length
()-
1
);
}
String
customerInfo
=
sf
.
append
(
"}"
).
toString
();
log
.
info
(
"组装的customerInfo明文:"
+
customerInfo
);
try
{
return
Base64
.
encodeBase64String
(
sf
.
toString
().
getBytes
(
encoding
));
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
return
customerInfo
;
}
/**
* 解析返回报文(后台通知)中的customerInfo域:<br>
* 解base64,如果带敏感信息加密 encryptedInfo 则将其解密并将 encryptedInfo中的域放到customerInfoMap返回<br>
* @param customerInfo<br>
* @param encoding<br>
* @return
*/
public
static
Map
<
String
,
String
>
parseCustomerInfo
(
String
customerInfo
,
String
encoding
)
{
Map
<
String
,
String
>
customerInfoMap
=
null
;
try
{
byte
[]
b
=
Base64
.
decodeBase64
(
customerInfo
);
String
customerInfoNoBase64
=
new
String
(
b
,
encoding
);
log
.
info
(
"解base64后===>"
+
customerInfoNoBase64
);
//去掉前后的{}
customerInfoNoBase64
=
customerInfoNoBase64
.
substring
(
1
,
customerInfoNoBase64
.
length
()
-
1
);
customerInfoMap
=
SDKUtil
.
parseRespString
(
customerInfoNoBase64
);
if
(
customerInfoMap
.
containsKey
(
"encryptedInfo"
))
{
String
encInfoStr
=
customerInfoMap
.
get
(
"encryptedInfo"
);
customerInfoMap
.
remove
(
"encryptedInfo"
);
String
encryptedInfoStr
=
decryptData
(
encInfoStr
,
encoding
);
Map
<
String
,
String
>
encryptedInfoMap
=
SDKUtil
.
parseRespString
(
encryptedInfoStr
);
customerInfoMap
.
putAll
(
encryptedInfoMap
);
}
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
return
customerInfoMap
;
}
/**
* 解析返回报文(后台通知)中的customerInfo域:<br>
* 解base64,如果带敏感信息加密 encryptedInfo 则将其解密并将 encryptedInfo中的域放到customerInfoMap返回<br>
* @param customerInfo<br>
* @param encoding<br>
* @return
*/
public
static
Map
<
String
,
String
>
parseCustomerInfo
(
String
customerInfo
,
String
certPath
,
String
certPwd
,
String
encoding
){
Map
<
String
,
String
>
customerInfoMap
=
null
;
try
{
byte
[]
b
=
Base64
.
decodeBase64
(
customerInfo
);
String
customerInfoNoBase64
=
new
String
(
b
,
encoding
);
log
.
info
(
"解base64后===>"
+
customerInfoNoBase64
);
//去掉前后的{}
customerInfoNoBase64
=
customerInfoNoBase64
.
substring
(
1
,
customerInfoNoBase64
.
length
()
-
1
);
customerInfoMap
=
SDKUtil
.
parseRespString
(
customerInfoNoBase64
);
if
(
customerInfoMap
.
containsKey
(
"encryptedInfo"
))
{
String
encInfoStr
=
customerInfoMap
.
get
(
"encryptedInfo"
);
customerInfoMap
.
remove
(
"encryptedInfo"
);
String
encryptedInfoStr
=
decryptData
(
encInfoStr
,
certPath
,
certPwd
,
encoding
);
Map
<
String
,
String
>
encryptedInfoMap
=
SDKUtil
.
parseRespString
(
encryptedInfoStr
);
customerInfoMap
.
putAll
(
encryptedInfoMap
);
}
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
return
customerInfoMap
;
}
/**
* 密码加密并做base64<br>
* @param accNo 卡号<br>
* @param pin 密码<br>
* @param encoding<br>
* @return 加密的内容<br>
*/
public
static
String
encryptPin
(
String
accNo
,
String
pin
,
String
encoding
)
{
byte
[]
pinblock
=
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
SecureUtil
.
pinblock
(
accNo
,
pin
);
return
Base64
.
encodeBase64String
(
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
SecureUtil
.
encrypt
(
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
CertUtil
.
getEncryptCert
().
pubKey
,
pinblock
));
}
/**
* 敏感信息加密并做base64(卡号,手机号,cvn2,有效期)<br>
* @param data 送 phoneNo,cvn2,有效期<br>
* @param encoding<br>
* @return 加密的密文<br>
*/
public
static
String
encryptData
(
String
data
,
String
encoding
)
{
try
{
return
Base64
.
encodeBase64String
(
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
SecureUtil
.
encrypt
(
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
CertUtil
.
getEncryptCert
().
pubKey
,
data
.
getBytes
(
encoding
)));
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
return
null
;
}
}
/**
* 敏感信息解密,使用配置文件acp_sdk.properties解密<br>
* @param base64EncryptedInfo 加密信息<br>
* @param encoding<br>
* @return 解密后的明文<br>
*/
public
static
String
decryptData
(
String
base64EncryptedInfo
,
String
encoding
)
{
return
new
String
(
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
SecureUtil
.
decrypt
(
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
CertUtil
.
getSignCertPrivateKey
(),
Base64
.
decodeBase64
(
base64EncryptedInfo
)),
Charset
.
forName
(
encoding
));
}
/**
* 敏感信息解密,通过传入的私钥解密<br>
* @param base64EncryptedInfo 加密信息<br>
* @param certPath 私钥文件(带全路径)<br>
* @param certPwd 私钥密码<br>
* @param encoding<br>
* @return
*/
public
static
String
decryptData
(
String
base64EncryptedInfo
,
String
certPath
,
String
certPwd
,
String
encoding
)
{
return
new
String
(
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
SecureUtil
.
decrypt
(
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
CertUtil
.
getSignCertPrivateKeyByStoreMap
(
certPath
,
certPwd
),
Base64
.
decodeBase64
(
base64EncryptedInfo
)),
Charset
.
forName
(
encoding
));
}
/**
* 5.0.0加密磁道信息,5.1.0接口请勿使用<br>
* @param trackData 待加密磁道数据<br>
* @param encoding 编码格式<br>
* @return 加密的密文<br>
* @deprecated
*/
public
static
String
encryptTrack
(
String
trackData
,
String
encoding
)
{
try
{
return
Base64
.
encodeBase64String
(
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
SecureUtil
.
encrypt
(
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
CertUtil
.
getEncryptTrackPublicKey
(),
trackData
.
getBytes
(
encoding
)));
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
return
null
;
}
}
/**
* 获取敏感信息加密证书的物理序列号<br>
* @return
*/
public
static
String
getEncryptCertId
(){
return
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
CertUtil
.
getEncryptCert
().
certId
;
}
/**
*
* 有卡交易信息域(cardTransData)构造<br>
* 所有子域需用“{}”包含,子域间以“&”符号链接。格式如下:{子域名1=值&子域名2=值&子域名3=值}<br>
* 说明:本示例仅供参考,开发时请根据接口文档中的报文要素组装<br>
*
* @param cardTransDataMap cardTransData的数据<br>
* @param requestData 必须包含merId、orderId、txnTime、txnAmt,磁道加密时需要使用<br>
* @param encoding 编码<br>
* @return
*/
public
static
String
getCardTransData
(
Map
<
String
,
String
>
cardTransDataMap
,
Map
<
String
,
String
>
requestData
,
String
encoding
)
{
{
StringBuffer
cardTransDataBuffer
=
new
StringBuffer
();
if
(
cardTransDataMap
.
containsKey
(
"track2Data"
)){
StringBuffer
track2Buffer
=
new
StringBuffer
();
track2Buffer
.
append
(
requestData
.
get
(
"merId"
))
.
append
(
SDKConstants
.
COLON
).
append
(
requestData
.
get
(
"orderId"
))
.
append
(
SDKConstants
.
COLON
).
append
(
requestData
.
get
(
"txnTime"
))
.
append
(
SDKConstants
.
COLON
).
append
(
requestData
.
get
(
"txnAmt"
)==
null
?
0
:
requestData
.
get
(
"txnAmt"
))
.
append
(
SDKConstants
.
COLON
).
append
(
cardTransDataMap
.
get
(
"track2Data"
));
cardTransDataMap
.
put
(
"track2Data"
,
AcpService
.
encryptData
(
track2Buffer
.
toString
(),
encoding
));
}
if
(
cardTransDataMap
.
containsKey
(
"track3Data"
)){
StringBuffer
track3Buffer
=
new
StringBuffer
();
track3Buffer
.
append
(
requestData
.
get
(
"merId"
))
.
append
(
SDKConstants
.
COLON
).
append
(
requestData
.
get
(
"orderId"
))
.
append
(
SDKConstants
.
COLON
).
append
(
requestData
.
get
(
"txnTime"
))
.
append
(
SDKConstants
.
COLON
).
append
(
requestData
.
get
(
"txnAmt"
)==
null
?
0
:
requestData
.
get
(
"txnAmt"
))
.
append
(
SDKConstants
.
COLON
).
append
(
cardTransDataMap
.
get
(
"track3Data"
));
cardTransDataMap
.
put
(
"track3Data"
,
AcpService
.
encryptData
(
track3Buffer
.
toString
(),
encoding
));
}
return
cardTransDataBuffer
.
append
(
SDKConstants
.
LEFT_BRACE
)
.
append
(
SDKUtil
.
createLinkString
(
cardTransDataMap
,
false
,
false
,
encoding
))
.
append
(
SDKConstants
.
RIGHT_BRACE
).
toString
();
}
}
/**
* 获取应答报文中的加密公钥证书,并存储到本地,备份原始证书,并自动替换证书<br>
* 更新成功则返回1,无更新返回0,失败异常返回-1<br>
* @return
*/
public
static
int
updateEncryptCert
(
Map
<
String
,
String
>
data
)
{
return
SDKUtil
.
updateEncryptCert
(
data
.
get
(
SDKConstants
.
param_encryptPubKeyCert
),
data
.
get
(
SDKConstants
.
param_certType
));
}
/**
* 对字符串做base64<br>
* @param rawStr<br>
* @param encoding<br>
* @return<br>
* @throws IOException
*/
public
static
String
base64Encode
(
String
rawStr
,
String
encoding
){
try
{
return
Base64
.
encodeBase64String
(
rawStr
.
getBytes
(
encoding
));
}
catch
(
UnsupportedEncodingException
e
)
{
throw
new
RuntimeException
(
"不认识这个编码?"
+
encoding
,
e
);
}
}
/**
* 对字符串做base64<br>
* @param base64Str<br>
* @param encoding<br>
* @return<br>
* @throws IOException
*/
public
static
String
base64Decode
(
String
base64Str
,
String
encoding
){
try
{
return
new
String
(
Base64
.
decodeBase64
(
base64Str
),
encoding
);
}
catch
(
UnsupportedEncodingException
e
)
{
throw
new
RuntimeException
(
"不认识这个编码?"
+
encoding
,
e
);
}
}
/**
* 组成{a=b&c=d}字符串
* @param map
* @return
*/
public
static
String
getKVField
(
Map
<
String
,
String
>
map
){
StringBuffer
sf
=
new
StringBuffer
();
String
info
=
sf
.
append
(
SDKConstants
.
LEFT_BRACE
)
.
append
(
SDKUtil
.
createLinkString
(
map
,
false
,
false
,
null
))
.
append
(
SDKConstants
.
RIGHT_BRACE
).
toString
();
return
info
;
}
/**
* 解析{a=b&c=d}字符串
* @param data
* @return
*/
public
static
Map
<
String
,
String
>
parseKVField
(
String
data
){
if
(
data
.
length
()
<=
2
)
return
null
;
data
=
data
.
substring
(
1
,
data
.
length
()
-
1
);
return
SDKUtil
.
parseRespString
(
data
);
}
}
liquidnet-bus-service/liquidnet-service-dragon/liquidnet-service-dragon-impl/src/main/java/com/liquidnet/service/dragon/channel/unionpay/sdk/CertUtil.java
0 → 100644
View file @
70db7894
/**
*
* Licensed Property to China UnionPay Co., Ltd.
*
* (C) Copyright of China UnionPay Co., Ltd. 2010
* All Rights Reserved.
*
*
* Modification History:
* =============================================================================
* Author Date Description
* ------------ ---------- ---------------------------------------------------
* xshu 2014-05-28 证书工具类.
* =============================================================================
*/
package
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.io.FileUtils
;
import
java.io.*
;
import
java.math.BigInteger
;
import
java.security.*
;
import
java.security.cert.*
;
import
java.security.spec.RSAPublicKeySpec
;
import
java.util.*
;
import
java.util.concurrent.ConcurrentHashMap
;
import
static
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
SDKConstants
.*;
import
static
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
SDKUtil
.
isEmpty
;
/**
* @ClassName: CertUtil
* @Description: acpsdk证书工具类,主要用于对证书的加载和使用
* @date 2016-7-22 下午2:46:20
*/
@Slf4j
public
class
CertUtil
{
/** 验签中级证书 */
private
static
X509Certificate
middleCert
=
null
;
/** 验签根证书 */
private
static
X509Certificate
rootCert
=
null
;
/** 5.0磁道加密公钥 */
private
static
PublicKey
encryptTrackKey
=
null
;
/** 签名私钥map:证书路径,私钥 */
private
final
static
Map
<
String
,
Cert
>
signCerts
=
new
ConcurrentHashMap
<
String
,
Cert
>();
/** 5.0接口验签证书Map:certId,公钥 */
private
static
Map
<
String
,
PublicKey
>
verifyCerts
=
new
ConcurrentHashMap
<
String
,
PublicKey
>();
/** 加密证书 */
private
static
Cert
encryptCert
=
null
;
/** 5.1接口验签证书Map:证书完整字符串,公钥 */
private
static
Map
<
String
,
PublicKey
>
verifyCerts510
=
new
ConcurrentHashMap
<
String
,
PublicKey
>();
/** 6.0统一支付加密pin用,其他接口请勿使用 */
private
static
Cert
pinEncryptCert
=
null
;
protected
static
class
Cert
{
protected
String
certId
;
protected
PublicKey
pubKey
;
protected
PrivateKey
priKey
;
}
static
{
addProvider
();
//向系统添加BC provider
init
();
}
/**
* 初始化所有证书.
*/
public
static
void
init
()
{
try
{
initSignCert
();
//初始化签名私钥证书
initMiddleCert
();
//初始化验签证书的中级证书
initRootCert
();
//初始化验签证书的根证书
initEncryptCert
();
//初始化加密公钥
initPinEncryptCert
();
//初始化pin加密公钥
initTrackKey
();
//构建磁道加密公钥
initValidateCertFromDir
();
//初始化所有的验签证书
}
catch
(
Exception
e
)
{
log
.
error
(
"init失败。"
,
e
);
}
}
/**
* 添加签名,验签,加密算法提供者
*/
private
static
void
addProvider
(){
if
(
Security
.
getProvider
(
"BC"
)
==
null
)
{
log
.
debug
(
"add BC provider"
);
Security
.
addProvider
(
new
org
.
bouncycastle
.
jce
.
provider
.
BouncyCastleProvider
());
}
else
{
Security
.
removeProvider
(
"BC"
);
//解决eclipse调试时tomcat自动重新加载时,BC存在不明原因异常的问题。
Security
.
addProvider
(
new
org
.
bouncycastle
.
jce
.
provider
.
BouncyCastleProvider
());
log
.
debug
(
"re-add BC provider"
);
}
printSysInfo
();
}
/**
*
* @param path
* @param pwd
* @return
*/
private
static
Cert
addSignCert
(
String
path
,
String
pwd
)
{
if
(
isEmpty
(
path
)
||
isEmpty
(
pwd
))
{
log
.
warn
(
"签名证书路径或证书密码为空。 停止加载签名私钥证书。"
);
return
null
;
}
final
String
type
=
"PKCS12"
;
//实际BC只支持PKCS12,不支持JKS,就不去管JKS了……
log
.
info
(
"加载签名私钥证书==>"
+
path
);
FileInputStream
fis
=
null
;
try
{
KeyStore
ks
=
KeyStore
.
getInstance
(
type
,
"BC"
);
log
.
debug
(
"Load RSA CertPath=["
+
path
+
"],Pwd=["
+
pwd
+
"]"
);
fis
=
new
FileInputStream
(
path
);
char
[]
nPassword
=
null
;
nPassword
=
null
==
pwd
||
""
.
equals
(
pwd
.
trim
())
?
null
:
pwd
.
toCharArray
();
if
(
null
!=
ks
)
{
ks
.
load
(
fis
,
nPassword
);
}
Enumeration
<
String
>
aliasenum
=
null
;
aliasenum
=
ks
.
aliases
();
String
keyAlias
=
null
;
if
(
aliasenum
.
hasMoreElements
())
{
keyAlias
=
aliasenum
.
nextElement
();
}
X509Certificate
cert
=
(
X509Certificate
)
ks
.
getCertificate
(
keyAlias
);
Cert
c
=
new
Cert
();
c
.
certId
=
cert
.
getSerialNumber
().
toString
(
10
);
c
.
priKey
=
(
PrivateKey
)
ks
.
getKey
(
keyAlias
,
pwd
.
toCharArray
());
c
.
pubKey
=
cert
.
getPublicKey
();
signCerts
.
put
(
path
,
c
);
log
.
info
(
"addSignCert Successful. CertId=["
+
c
.
certId
+
"]"
);
return
c
;
}
catch
(
Exception
e
)
{
log
.
error
(
"addSignCert Error"
,
e
);
}
finally
{
if
(
null
!=
fis
)
try
{
fis
.
close
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
return
null
;
}
/**
* 指定路径读个x509证书
* @param path
* @return
*/
public
static
X509Certificate
readX509Cert
(
String
path
)
{
X509Certificate
cert
=
null
;
CertificateFactory
cf
=
null
;
FileInputStream
in
=
null
;
try
{
cf
=
CertificateFactory
.
getInstance
(
"X.509"
,
"BC"
);
in
=
new
FileInputStream
(
path
);
cert
=
(
X509Certificate
)
cf
.
generateCertificate
(
in
);
}
catch
(
FileNotFoundException
e
)
{
log
.
error
(
"readX509Cert Error File Not Found: "
+
path
,
e
);
}
catch
(
Exception
e
)
{
log
.
error
(
"readX509Cert Error"
,
e
);
}
finally
{
if
(
null
!=
in
)
{
try
{
in
.
close
();
}
catch
(
IOException
e
)
{
}
}
}
return
cert
;
}
/**
* 用配置文件acp_sdk.properties中配置的私钥路径和密码 加载签名证书,会清空重新加载,一般仅第一次加载时调用即可
*/
private
static
void
initSignCert
()
{
signCerts
.
clear
();
String
path
=
SDKConfig
.
getConfig
().
getSignCertPath
();
String
pwd
=
SDKConfig
.
getConfig
().
getSignCertPwd
();
if
(
isEmpty
(
path
)
||
isEmpty
(
pwd
))
{
log
.
warn
(
SDKConfig
.
SDK_SIGNCERT_PATH
+
" or "
+
SDKConfig
.
SDK_SIGNCERT_PWD
+
" is empty"
);
return
;
}
Cert
cert
=
addSignCert
(
path
,
pwd
);
log
.
info
(
"读取配置文件默认签名证书==>"
+
path
+
(
cert
!=
null
?
"成功"
:
"失败"
));
}
/**
* 用配置文件acp_sdk.properties配置路径 加载5.1验签证书中级证书
*/
private
static
void
initMiddleCert
()
{
String
path
=
SDKConfig
.
getConfig
().
getMiddleCertPath
();
if
(
isEmpty
(
path
)){
log
.
warn
(
SDKConfig
.
SDK_MIDDLECERT_PATH
+
" is empty"
);
return
;
}
middleCert
=
readX509Cert
(
path
);
log
.
info
(
"加载中级证书==>"
+
path
+
(
middleCert
!=
null
?
"成功"
:
"失败"
));
}
/**
* 用配置文件acp_sdk.properties配置路径 加载5.1验签证书根证书
*/
private
static
void
initRootCert
()
{
String
path
=
SDKConfig
.
getConfig
().
getRootCertPath
();
if
(
isEmpty
(
path
)){
log
.
warn
(
SDKConfig
.
SDK_ROOTCERT_PATH
+
" is empty"
);
return
;
}
rootCert
=
readX509Cert
(
path
);
log
.
info
(
"加载根证书==>"
+
path
+
(
rootCert
!=
null
?
"成功"
:
"失败"
));
}
/**
* 用配置文件acp_sdk.properties配置路径 加载磁道公钥
*/
private
static
void
initTrackKey
()
{
String
modulus
=
SDKConfig
.
getConfig
().
getEncryptTrackKeyModulus
();
String
exponent
=
SDKConfig
.
getConfig
().
getEncryptTrackKeyExponent
();
if
(
isEmpty
(
modulus
)
||
isEmpty
(
exponent
)){
log
.
warn
(
SDKConfig
.
SDK_ENCRYPTTRACKKEY_MODULUS
+
" or "
+
SDKConfig
.
SDK_ENCRYPTTRACKKEY_EXPONENT
+
" is empty"
);
return
;
}
encryptTrackKey
=
getPublicKey
(
modulus
,
exponent
);
log
.
info
(
"加载5.0磁道公钥==>"
+
(
encryptTrackKey
!=
null
?
"成功"
:
"失败"
));
}
/**
* 用配置文件acp_sdk.properties配置路径 加载验签证书
*/
private
static
void
initValidateCertFromDir
()
{
verifyCerts
.
clear
();
String
dir
=
SDKConfig
.
getConfig
().
getValidateCertDir
();
if
(
isEmpty
(
dir
))
{
log
.
error
(
"WARN: acpsdk.validateCert.dir is empty"
);
return
;
}
log
.
info
(
"加载验证签名证书目录==>"
+
dir
+
" 注:如果请求报文中version=5.1.0那么此验签证书目录使用不到,可以不需要设置(version=5.0.0必须设置)。"
);
File
fileDir
=
new
File
(
dir
);
File
[]
files
=
fileDir
.
listFiles
(
new
CerFilter
());
for
(
int
i
=
0
;
i
<
files
.
length
;
i
++)
{
File
file
=
files
[
i
];
try
{
X509Certificate
verifyCert
=
readX509Cert
(
file
.
getAbsolutePath
());
if
(
verifyCert
==
null
)
{
continue
;
}
String
certId
=
verifyCert
.
getSerialNumber
().
toString
(
10
);
verifyCerts
.
put
(
certId
,
verifyCert
.
getPublicKey
());
log
.
info
(
"["
+
file
.
getAbsolutePath
()
+
"][CertId="
+
certId
+
"]"
);
}
catch
(
Exception
e
)
{
log
.
error
(
"Load verify cert error, "
+
file
.
getAbsolutePath
(),
e
);
}
}
log
.
info
(
"LoadVerifyCert Finish"
);
}
/**
* 用配置文件acp_sdk.properties配置路径 加载敏感信息加密证书
*/
private
static
void
initEncryptCert
()
{
String
path
=
SDKConfig
.
getConfig
().
getEncryptCertPath
();
if
(
isEmpty
(
path
)){
log
.
warn
(
SDKConfig
.
SDK_ENCRYPTCERT_PATH
+
" is empty"
);
return
;
}
X509Certificate
encryptCert
=
readX509Cert
(
path
);
log
.
info
(
"加载敏感信息加密证书==>"
+
path
+
(
encryptCert
!=
null
?
"成功"
:
"失败"
));
if
(
encryptCert
!=
null
)
{
Cert
c
=
new
Cert
();
c
.
certId
=
encryptCert
.
getSerialNumber
().
toString
(
10
);
c
.
pubKey
=
encryptCert
.
getPublicKey
();
CertUtil
.
encryptCert
=
c
;
}
}
/**
* 用配置文件acp_sdk.properties配置路径 加载6.0统一支付产品pin加密证书
*/
private
static
void
initPinEncryptCert
()
{
String
path
=
SDKConfig
.
getConfig
().
getPinEncryptCertPath
();
if
(
isEmpty
(
path
)){
log
.
warn
(
SDKConfig
.
SDK_PINENCRYPTCERT_PATH
+
" is empty"
);
return
;
}
X509Certificate
encryptCert
=
readX509Cert
(
path
);
log
.
info
(
"加载6.0统一支付产品pin加密证书==>"
+
path
+
(
encryptCert
!=
null
?
"成功"
:
"失败"
));
if
(
encryptCert
!=
null
)
{
Cert
c
=
new
Cert
();
c
.
certId
=
encryptCert
.
getSerialNumber
().
toString
(
10
);
c
.
pubKey
=
encryptCert
.
getPublicKey
();
CertUtil
.
pinEncryptCert
=
c
;
}
}
/**
*
*/
private
static
Cert
getSignCert
()
{
String
path
=
SDKConfig
.
getConfig
().
getSignCertPath
();
String
pwd
=
SDKConfig
.
getConfig
().
getSignCertPwd
();
if
(
isEmpty
(
path
)
||
isEmpty
(
pwd
))
{
log
.
error
(
"未配置默认签名证书时无法调用此方法。"
);
return
null
;
}
return
getSignCert
(
path
,
pwd
);
}
/**
*
* @param path
* @param pwd
* @return
*/
private
static
Cert
getSignCert
(
String
path
,
String
pwd
)
{
if
(
isEmpty
(
path
)
||
isEmpty
(
pwd
))
{
log
.
error
(
"传入的签名路径或密码为空。"
);
return
null
;
}
if
(!
signCerts
.
containsKey
(
path
)){
addSignCert
(
path
,
pwd
);
}
Cert
c
=
signCerts
.
get
(
path
);
if
(
c
==
null
)
{
log
.
error
(
"未成功获取签名证书。"
);
return
null
;
}
return
c
;
}
/**
* 获取敏感信息加密证书PublicKey
*
* @return
*/
protected
static
Cert
getEncryptCert
()
{
if
(
CertUtil
.
encryptCert
==
null
)
{
initEncryptCert
();
}
return
CertUtil
.
encryptCert
;
}
/**
* 获取敏感信息加密证书PublicKey
*
* @return
*/
protected
static
Cert
getPinEncryptCert
()
{
if
(
CertUtil
.
pinEncryptCert
==
null
)
{
initPinEncryptCert
();
}
return
CertUtil
.
pinEncryptCert
;
}
/**
* 重置敏感信息加密证书公钥。
*/
public
static
int
resetEncryptCertPublicKey
(
String
strCert
)
{
if
(
isEmpty
(
strCert
))
{
log
.
error
(
"传入证书信息为空。"
);
return
-
1
;
}
X509Certificate
x509Cert
=
CertUtil
.
genCertificateByStr
(
strCert
);
// 没换,不需要更新
if
(
CertUtil
.
getEncryptCert
().
certId
.
equals
(
x509Cert
.
getSerialNumber
().
toString
(
10
)))
{
log
.
info
(
"返回证书和原证书一样,不用更新。"
);
return
0
;
}
final
String
localCertPath
=
SDKConfig
.
getConfig
().
getEncryptCertPath
();
if
(
isEmpty
(
localCertPath
)){
log
.
error
(
"未配置加密证书路径,无法执行此方法。"
);
return
-
1
;
}
File
f
=
new
File
(
localCertPath
);
if
(!
f
.
exists
())
{
log
.
warn
(
"原加密证书不存在:"
+
localCertPath
);
}
else
{
// 将本地证书进行备份存储
int
i
=
localCertPath
.
lastIndexOf
(
POINT
);
String
leftFileName
=
localCertPath
.
substring
(
0
,
i
);
String
rightFileName
=
localCertPath
.
substring
(
i
+
1
);
String
newFileName
=
leftFileName
+
"_backup"
+
POINT
+
rightFileName
;
try
{
FileUtils
.
copyFile
(
f
,
new
File
(
newFileName
));
log
.
info
(
"原加密证书备份成功。"
);
}
catch
(
IOException
e
)
{
log
.
error
(
"原加密证书备份失败,停止改证书。"
,
e
);
return
-
1
;
}
}
// 备份成功,进行新证书的存储
try
{
FileUtils
.
writeByteArrayToFile
(
f
,
strCert
.
getBytes
(),
false
);
log
.
info
(
"加密证书更新成功。"
);
initEncryptCert
();
return
1
;
}
catch
(
IOException
e
)
{
log
.
error
(
"加密证书更新失败。"
,
e
);
return
-
1
;
}
}
/**
* 重置pin敏感信息加密证书公钥。
*/
public
static
int
resetPinEncryptCertPublicKey
(
String
strCert
)
{
if
(
isEmpty
(
strCert
))
{
log
.
error
(
"传入证书信息为空。"
);
return
-
1
;
}
X509Certificate
x509Cert
=
CertUtil
.
genCertificateByStr
(
strCert
);
// 没换,不需要更新
if
(
CertUtil
.
getPinEncryptCert
().
certId
.
equals
(
x509Cert
.
getSerialNumber
().
toString
(
10
)))
{
log
.
info
(
"返回证书和原证书一样,不用更新。"
);
return
0
;
}
final
String
localCertPath
=
SDKConfig
.
getConfig
().
getPinEncryptCertPath
();
if
(
isEmpty
(
localCertPath
)){
log
.
error
(
"未配置加密证书路径,无法执行此方法。"
);
return
-
1
;
}
File
f
=
new
File
(
localCertPath
);
if
(!
f
.
exists
())
{
log
.
warn
(
"原加密证书不存在:"
+
localCertPath
);
}
else
{
// 将本地证书进行备份存储
int
i
=
localCertPath
.
lastIndexOf
(
POINT
);
String
leftFileName
=
localCertPath
.
substring
(
0
,
i
);
String
rightFileName
=
localCertPath
.
substring
(
i
+
1
);
String
newFileName
=
leftFileName
+
"_backup"
+
POINT
+
rightFileName
;
try
{
FileUtils
.
copyFile
(
f
,
new
File
(
newFileName
));
log
.
info
(
"原加密证书备份成功。"
);
}
catch
(
IOException
e
)
{
log
.
error
(
"原加密证书备份失败,停止改证书。"
,
e
);
return
-
1
;
}
}
// 备份成功,进行新证书的存储
try
{
FileUtils
.
writeByteArrayToFile
(
f
,
strCert
.
getBytes
(),
false
);
log
.
info
(
"加密证书更新成功。"
);
initPinEncryptCert
();
return
1
;
}
catch
(
IOException
e
)
{
log
.
error
(
"加密证书更新失败。"
,
e
);
return
-
1
;
}
}
/**
* 获取磁道加密证书PublicKey
*
* @return
*/
public
static
PublicKey
getEncryptTrackPublicKey
()
{
if
(
null
==
encryptTrackKey
)
{
initTrackKey
();
}
return
encryptTrackKey
;
}
/**
* 通过certId获取验签证书Map中对应证书PublicKey
*
* @param certId 证书物理序号
* @return 通过证书编号获取到的公钥
*/
public
static
PublicKey
getValidatePublicKey
(
String
certId
)
{
if
(
certId
==
null
)
{
log
.
error
(
"没有传入certId."
);
return
null
;
}
if
(!
verifyCerts
.
containsKey
(
certId
))
{
initValidateCertFromDir
();
}
PublicKey
result
=
verifyCerts
.
get
(
certId
);
if
(
result
==
null
)
{
log
.
error
(
"缺少certId=["
+
certId
+
"]对应的验签证书."
);
return
null
;
}
return
result
;
}
/**
* 获取配置文件acp_sdk.properties中配置的签名私钥证书certId
*
* @return 证书的物理编号
*/
public
static
String
getSignCertId
()
{
Cert
c
=
getSignCert
();
if
(
c
==
null
)
return
null
;
return
c
.
certId
;
}
/**
* 获取配置文件acp_sdk.properties中配置的签名私钥证书私钥
*
* @return 证书的物理编号
*/
public
static
PrivateKey
getSignCertPrivateKey
()
{
Cert
c
=
getSignCert
();
if
(
c
==
null
)
return
null
;
return
c
.
priKey
;
}
/**
*
* @param path
* @param pwd
* @return
*/
public
static
String
getCertIdByKeyStoreMap
(
String
path
,
String
pwd
)
{
Cert
c
=
getSignCert
(
path
,
pwd
);
if
(
c
==
null
)
return
null
;
return
c
.
certId
;
}
/**
*
* @param path
* @param pwd
* @return
*/
public
static
PrivateKey
getSignCertPrivateKeyByStoreMap
(
String
path
,
String
pwd
)
{
Cert
c
=
getSignCert
(
path
,
pwd
);
if
(
c
==
null
)
return
null
;
return
c
.
priKey
;
}
// /**
// * 获取敏感信息加密证书的certId
// *
// * @return
// */
// public static String getEncryptCertId() {
// Cert c = getEncryptCert();
// if(c == null) return null;
// return c.certId;
// }
//
//
// public static PublicKey getEncryptCertPublicKey(){
// Cert c = getEncryptCert();
// if(c == null) return null;
// return c.pubKey;
// }
//
// /**
// * 获取6.0统一支付产品pin加密证书的certId
// *
// * @return
// */
// public static String getPinEncryptCertId() {
// Cert c = getPinEncryptCert();
// if(c == null) return null;
// return c.certId;
// }
//
//
// public static PublicKey getPinEncryptCertPublicKey(){
// Cert c = getEncryptCert();
// if(c == null) return null;
// return c.pubKey;
// }
/**
* 使用模和指数生成RSA公钥 注意:此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同
*
* @param modulus
* 模
* @param exponent
* 指数
* @return
*/
private
static
PublicKey
getPublicKey
(
String
modulus
,
String
exponent
)
{
try
{
BigInteger
b1
=
new
BigInteger
(
modulus
);
BigInteger
b2
=
new
BigInteger
(
exponent
);
KeyFactory
keyFactory
=
KeyFactory
.
getInstance
(
"RSA"
,
"BC"
);
RSAPublicKeySpec
keySpec
=
new
RSAPublicKeySpec
(
b1
,
b2
);
return
keyFactory
.
generatePublic
(
keySpec
);
}
catch
(
Exception
e
)
{
log
.
error
(
"构造RSA公钥失败:"
+
e
);
return
null
;
}
}
/**
* 将字符串转换为X509Certificate对象.
*
* @param x509CertString
* @return
*/
public
static
X509Certificate
genCertificateByStr
(
String
x509CertString
)
{
X509Certificate
x509Cert
=
null
;
try
{
CertificateFactory
cf
=
CertificateFactory
.
getInstance
(
"X.509"
,
"BC"
);
InputStream
tIn
=
new
ByteArrayInputStream
(
x509CertString
.
getBytes
(
"ISO-8859-1"
));
x509Cert
=
(
X509Certificate
)
cf
.
generateCertificate
(
tIn
);
}
catch
(
Exception
e
)
{
log
.
error
(
"gen certificate error"
,
e
);
}
return
x509Cert
;
}
/**
* 从配置文件acp_sdk.properties中获取验签公钥使用的中级证书
* @return
*/
private
static
X509Certificate
getMiddleCert
()
{
String
path
=
SDKConfig
.
getConfig
().
getMiddleCertPath
();
if
(
isEmpty
(
path
))
{
log
.
error
(
"未配置中级证书时无法调用此方法。"
);
return
null
;
}
if
(
middleCert
==
null
)
{
initMiddleCert
();
}
return
middleCert
;
}
/**
* 从配置文件acp_sdk.properties中获取验签公钥使用的根证书
* @return
*/
private
static
X509Certificate
getRootCert
()
{
String
path
=
SDKConfig
.
getConfig
().
getRootCertPath
();
if
(
isEmpty
(
path
))
{
log
.
error
(
"未配置根证书时无法调用此方法。"
);
return
null
;
}
if
(
rootCert
==
null
)
{
initRootCert
();
}
return
rootCert
;
}
/**
* 获取证书的CN
* @param aCert
* @return
*/
public
static
String
getIdentitiesFromCertficate
(
X509Certificate
aCert
)
{
String
tDN
=
aCert
.
getSubjectDN
().
toString
();
String
tPart
=
""
;
if
((
tDN
!=
null
))
{
String
tSplitStr
[]
=
tDN
.
substring
(
tDN
.
indexOf
(
"CN="
)).
split
(
"@"
);
if
(
tSplitStr
!=
null
&&
tSplitStr
.
length
>
2
&&
tSplitStr
[
2
]
!=
null
)
tPart
=
tSplitStr
[
2
];
}
return
tPart
;
}
/**
* 验证书链。
* @param cert
* @return
*/
public
static
boolean
verifyCertificateChain
(
X509Certificate
cert
,
X509Certificate
middleCert
,
X509Certificate
rootCert
){
if
(
null
==
cert
)
{
log
.
error
(
"cert must Not null"
);
return
false
;
}
if
(
null
==
middleCert
)
{
log
.
error
(
"middleCert must Not null"
);
return
false
;
}
if
(
null
==
rootCert
)
{
log
.
error
(
"rootCert or cert must Not null"
);
return
false
;
}
try
{
X509CertSelector
selector
=
new
X509CertSelector
();
selector
.
setCertificate
(
cert
);
Set
<
TrustAnchor
>
trustAnchors
=
new
HashSet
<
TrustAnchor
>();
trustAnchors
.
add
(
new
TrustAnchor
(
rootCert
,
null
));
PKIXBuilderParameters
pkixParams
=
new
PKIXBuilderParameters
(
trustAnchors
,
selector
);
Set
<
X509Certificate
>
intermediateCerts
=
new
HashSet
<
X509Certificate
>();
intermediateCerts
.
add
(
rootCert
);
intermediateCerts
.
add
(
middleCert
);
intermediateCerts
.
add
(
cert
);
pkixParams
.
setRevocationEnabled
(
false
);
CertStore
intermediateCertStore
=
CertStore
.
getInstance
(
"Collection"
,
new
CollectionCertStoreParameters
(
intermediateCerts
),
"BC"
);
pkixParams
.
addCertStore
(
intermediateCertStore
);
CertPathBuilder
builder
=
CertPathBuilder
.
getInstance
(
"PKIX"
,
"BC"
);
@SuppressWarnings
(
"unused"
)
PKIXCertPathBuilderResult
result
=
(
PKIXCertPathBuilderResult
)
builder
.
build
(
pkixParams
);
log
.
info
(
"verify certificate chain succeed."
);
return
true
;
}
catch
(
java
.
security
.
cert
.
CertPathBuilderException
e
){
log
.
error
(
"verify certificate chain fail."
,
e
);
}
catch
(
Exception
e
)
{
log
.
error
(
"verify certificate chain exception: "
,
e
);
}
return
false
;
}
public
static
PublicKey
verifyAndGetVerifyPubKey
(
String
x509CertString
){
if
(
isEmpty
(
x509CertString
))
{
log
.
error
(
"验签公钥证书传了空。"
);
return
null
;
}
if
(
verifyCerts510
.
containsKey
(
x509CertString
))
return
verifyCerts510
.
get
(
x509CertString
);
log
.
debug
(
"验签公钥证书:["
+
x509CertString
+
"]"
);
X509Certificate
x509Cert
=
CertUtil
.
genCertificateByStr
(
x509CertString
);
if
(
x509Cert
==
null
)
{
log
.
error
(
"convert signPubKeyCert failed"
);
return
null
;
}
// 验证证书链
if
(!
CertUtil
.
verifyCertificate
(
x509Cert
))
{
log
.
error
(
"验证公钥证书失败,证书信息:["
+
x509CertString
+
"]"
);
return
null
;
}
log
.
info
(
"验证公钥验证成功:["
+
x509Cert
.
getSerialNumber
().
toString
(
10
)
+
"]"
);
PublicKey
publicKey
=
x509Cert
.
getPublicKey
();
verifyCerts510
.
put
(
x509CertString
,
publicKey
);
return
publicKey
;
}
/**
*
* @param cert
* @return
*/
private
static
boolean
verifyCertificate
(
X509Certificate
cert
)
{
if
(
null
==
cert
)
{
log
.
error
(
"cert must Not null"
);
return
false
;
}
try
{
cert
.
checkValidity
();
//验证有效期
if
(!
verifyCertificateChain
(
cert
,
CertUtil
.
getMiddleCert
(),
CertUtil
.
getRootCert
())){
return
false
;
}
}
catch
(
Exception
e
)
{
log
.
error
(
"verifyCertificate fail"
,
e
);
return
false
;
}
if
(
SDKConfig
.
getConfig
().
isIfValidateCNName
()){
// 验证公钥是否属于银联
if
(!
UNIONPAY_CNNAME
.
equals
(
CertUtil
.
getIdentitiesFromCertficate
(
cert
)))
{
log
.
error
(
"cer owner is not CUP:"
+
CertUtil
.
getIdentitiesFromCertficate
(
cert
));
return
false
;
}
}
else
{
// 验证公钥是否属于银联
if
(!
UNIONPAY_CNNAME
.
equals
(
CertUtil
.
getIdentitiesFromCertficate
(
cert
))
&&
!
"00040000:SIGN"
.
equals
(
CertUtil
.
getIdentitiesFromCertficate
(
cert
)))
{
log
.
error
(
"cer owner is not CUP:"
+
CertUtil
.
getIdentitiesFromCertficate
(
cert
));
return
false
;
}
}
return
true
;
}
/**
* 打印系统环境信息
*/
private
static
void
printSysInfo
()
{
log
.
info
(
"================= SYS INFO begin===================="
);
log
.
info
(
"os_name:"
+
System
.
getProperty
(
"os.name"
));
log
.
info
(
"os_arch:"
+
System
.
getProperty
(
"os.arch"
));
log
.
info
(
"os_version:"
+
System
.
getProperty
(
"os.version"
));
log
.
info
(
"java_vm_specification_version:"
+
System
.
getProperty
(
"java.vm.specification.version"
));
log
.
info
(
"java_vm_specification_vendor:"
+
System
.
getProperty
(
"java.vm.specification.vendor"
));
log
.
info
(
"java_vm_specification_name:"
+
System
.
getProperty
(
"java.vm.specification.name"
));
log
.
info
(
"java_vm_version:"
+
System
.
getProperty
(
"java.vm.version"
));
log
.
info
(
"java_vm_name:"
+
System
.
getProperty
(
"java.vm.name"
));
log
.
info
(
"java.version:"
+
System
.
getProperty
(
"java.version"
));
log
.
info
(
"java.vm.vendor=["
+
System
.
getProperty
(
"java.vm.vendor"
)
+
"]"
);
log
.
info
(
"java.version=["
+
System
.
getProperty
(
"java.version"
)
+
"]"
);
printProviders
();
log
.
info
(
"================= SYS INFO end====================="
);
}
/**
* 打jre中印算法提供者列表
*/
private
static
void
printProviders
()
{
log
.
info
(
"Providers List:"
);
Provider
[]
providers
=
Security
.
getProviders
();
for
(
int
i
=
0
;
i
<
providers
.
length
;
i
++)
{
log
.
info
(
i
+
1
+
"."
+
providers
[
i
].
getName
());
}
}
/**
* 证书文件过滤器
*
*/
static
class
CerFilter
implements
FilenameFilter
{
public
boolean
isCer
(
String
name
)
{
return
name
.
toLowerCase
().
endsWith
(
".cer"
);
}
public
boolean
accept
(
File
dir
,
String
name
)
{
return
isCer
(
name
);
}
}
public
static
Collection
<
PublicKey
>
getVerifySignPubKeys
(){
return
verifyCerts
.
values
();
}
}
liquidnet-bus-service/liquidnet-service-dragon/liquidnet-service-dragon-impl/src/main/java/com/liquidnet/service/dragon/channel/unionpay/sdk/HttpsUtil.java
0 → 100644
View file @
70db7894
package
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
;
import
lombok.extern.slf4j.Slf4j
;
import
javax.net.ssl.*
;
import
java.io.*
;
import
java.net.HttpURLConnection
;
import
java.net.URL
;
import
java.security.*
;
import
java.security.cert.CertificateException
;
import
java.security.cert.X509Certificate
;
import
java.util.Map
;
import
java.util.Map.Entry
;
import
java.util.TreeMap
;
/**
* http:
* 直接用get和post方法。
*
* 单向https用默认信任库验证证书:
* 直接用get和post方法。
*
* 单向https不验证证书:
* 用get和post方法时地址前面加个u,比如uhttps://101.231.204.80:5000/xxxx。
*
* 双向https:
* 先调addSslConf加客户端证书和信任库。
* 用get和post方法时地址前面加个自己写的tag替换掉https,比如cloudpos://101.231.204.80:5000/xxxx。
*/
@Slf4j
public
class
HttpsUtil
{
// static {//商户如果通过代理访问需要的改动点
// System.setProperty("proxyType", "4");
// System.setProperty("proxyPort", "8080");
// System.setProperty("proxyHost", "172.16.1.245");
// System.setProperty("proxySet", "true");
// }
public
static
byte
[]
send
(
String
urlStr
,
byte
[]
data
,
Map
<
String
,
String
>
reqHeader
,
String
requestMethod
){
String
tag
=
null
;
if
(!
urlStr
.
startsWith
(
"https://"
)
&&
!
urlStr
.
startsWith
(
"http://"
))
{
int
idx
=
urlStr
.
indexOf
(
"://"
);
if
(
idx
<=
0
)
{
log
.
error
(
"errurl ["
+
urlStr
+
"]"
);
}
tag
=
urlStr
.
substring
(
0
,
idx
);
//取tag
urlStr
=
"https"
+
urlStr
.
substring
(
idx
);
//地址转回https
}
if
(
data
!=
null
)
log
.
debug
(
requestMethod
+
" to ["
+
urlStr
+
"]: "
+
new
String
(
data
));
else
log
.
debug
(
requestMethod
+
" to ["
+
urlStr
+
"]"
);
HttpURLConnection
httpURLConnection
=
null
;
try
{
URL
url
=
new
URL
(
urlStr
);
httpURLConnection
=
(
HttpURLConnection
)
url
.
openConnection
();
httpURLConnection
.
setConnectTimeout
(
15000
);
// 连接超时时间
httpURLConnection
.
setReadTimeout
(
90000
);
// 读取结果超时时间
httpURLConnection
.
setDoInput
(
true
);
// 可读
httpURLConnection
.
setDoOutput
(
true
);
// 可写
httpURLConnection
.
setUseCaches
(
false
);
// 取消缓存
for
(
Entry
<
String
,
String
>
kv
:
reqHeader
.
entrySet
()){
httpURLConnection
.
setRequestProperty
(
kv
.
getKey
(),
kv
.
getValue
());
}
httpURLConnection
.
setRequestMethod
(
requestMethod
);
if
(
tag
!=
null
)
{
HttpsURLConnection
husn
=
(
HttpsURLConnection
)
httpURLConnection
;
if
(
ssLSocketFactoryMap
.
containsKey
(
tag
))
{
husn
.
setSSLSocketFactory
(
ssLSocketFactoryMap
.
get
(
tag
));
}
if
(
ifVerifyHostnameMap
.
get
(
tag
)
==
false
)
{
husn
.
setHostnameVerifier
(
trustAllHostnameVerifier
);
}
}
httpURLConnection
.
connect
();
if
(
data
!=
null
)
{
httpURLConnection
.
getOutputStream
().
write
(
data
);
httpURLConnection
.
getOutputStream
().
flush
();
}
int
httpCode
=
httpURLConnection
.
getResponseCode
();
String
encoding
=
httpURLConnection
.
getContentEncoding
();
if
(
encoding
==
null
)
encoding
=
"UTF-8"
;
byte
[]
respBody
;
if
(
httpCode
!=
HttpURLConnection
.
HTTP_OK
){
respBody
=
read
(
httpURLConnection
.
getErrorStream
());
log
.
error
(
"HTTP RESP["
+
httpCode
+
"]: "
+
new
String
(
respBody
,
encoding
));
}
else
{
respBody
=
read
(
httpURLConnection
.
getInputStream
());
log
.
debug
(
"HTTP RESP["
+
httpCode
+
"]: "
+
new
String
(
respBody
,
encoding
));
}
return
respBody
;
}
catch
(
Exception
e
)
{
log
.
error
(
"["
+
urlStr
+
"] "
+
e
.
getMessage
()
+
" <- "
+
e
.
getClass
().
getName
(),
e
);
}
finally
{
if
(
httpURLConnection
!=
null
)
httpURLConnection
.
disconnect
();
}
return
null
;
}
public
static
byte
[]
post
(
String
url
,
byte
[]
data
,
Map
<
String
,
String
>
reqHeader
){
return
send
(
url
,
data
,
reqHeader
,
"POST"
);
}
public
static
byte
[]
post
(
String
url
,
byte
[]
data
){
return
post
(
url
,
data
,
new
TreeMap
<
String
,
String
>(){
private
static
final
long
serialVersionUID
=
-
2761292859751696874L
;
{
put
(
"Content-Type"
,
"application/x-www-form-urlencoded"
);
}
});
}
public
static
byte
[]
get
(
String
url
,
Map
<
String
,
String
>
reqHeader
){
return
send
(
url
,
null
,
reqHeader
,
"GET"
);
}
public
static
byte
[]
get
(
String
url
){
return
send
(
url
,
null
,
new
TreeMap
<
String
,
String
>(){
private
static
final
long
serialVersionUID
=
-
7225134807859941048L
;
{
put
(
"Content-Type"
,
"application/x-www-form-urlencoded"
);
}
},
"GET"
);
}
private
static
byte
[]
read
(
InputStream
in
)
throws
IOException
{
byte
[]
buf
=
new
byte
[
1024
];
int
length
=
0
;
ByteArrayOutputStream
bout
=
new
ByteArrayOutputStream
();
while
((
length
=
in
.
read
(
buf
,
0
,
buf
.
length
))
>
0
)
{
bout
.
write
(
buf
,
0
,
length
);
}
bout
.
flush
();
return
bout
.
toByteArray
();
}
private
static
Map
<
String
,
SSLSocketFactory
>
ssLSocketFactoryMap
=
new
TreeMap
<
String
,
SSLSocketFactory
>();
private
static
Map
<
String
,
Boolean
>
ifVerifyHostnameMap
=
new
TreeMap
<
String
,
Boolean
>();
private
static
final
X509TrustManager
trustAllX509TrustManager
=
new
X509TrustManager
()
{
@Override
public
void
checkClientTrusted
(
X509Certificate
[]
chain
,
String
authType
)
throws
CertificateException
{
}
@Override
public
void
checkServerTrusted
(
X509Certificate
[]
chain
,
String
authType
)
throws
CertificateException
{
}
@Override
public
X509Certificate
[]
getAcceptedIssuers
()
{
return
null
;
}
};
private
static
final
HostnameVerifier
trustAllHostnameVerifier
=
new
HostnameVerifier
()
{
public
boolean
verify
(
String
hostname
,
SSLSession
session
)
{
return
true
;
}
};
/**
*
* @param tag
* @param keyStoreJksPath 客户端证书库jks。设空时效果等同为单向https。
* @param keyStoreJksPwd
* @param trustStoreJksPath 信任库jks。设空时效果等同都信任。
* @param trustStoreJksPwd
* @param verifyHostname 是否需要验证hostname。
* @return
*/
public
static
boolean
addSslConf
(
String
tag
,
String
keyStoreJksPath
,
String
keyStoreJksPwd
,
String
trustStoreJksPath
,
String
trustStoreJksPwd
,
boolean
verifyHostname
)
{
if
(
ssLSocketFactoryMap
.
containsKey
(
tag
))
{
log
.
warn
(
"addSslConf err: ["
+
tag
+
"] has been added"
);
return
false
;
}
try
{
KeyManagerFactory
kmf
=
null
;
if
(
keyStoreJksPath
!=
null
)
{
KeyStore
keyStore
=
loadKeyStore
(
keyStoreJksPath
,
keyStoreJksPwd
,
"JKS"
);
if
(
keyStore
==
null
)
{
return
false
;
}
kmf
=
KeyManagerFactory
.
getInstance
(
KeyManagerFactory
.
getDefaultAlgorithm
());
kmf
.
init
(
keyStore
,
keyStoreJksPwd
.
toCharArray
());
}
TrustManagerFactory
tmf
=
null
;
if
(
trustStoreJksPath
!=
null
)
{
KeyStore
trustStore
=
loadKeyStore
(
trustStoreJksPath
,
trustStoreJksPwd
,
"JKS"
);
if
(
trustStore
==
null
)
{
return
false
;
}
tmf
=
TrustManagerFactory
.
getInstance
(
KeyManagerFactory
.
getDefaultAlgorithm
());
tmf
.
init
(
trustStore
);
}
SSLContext
sslContext
=
SSLContext
.
getInstance
(
"TLS"
);
KeyManager
[]
keyManagers
=
kmf
==
null
?
null
:
kmf
.
getKeyManagers
();
TrustManager
[]
trustManagers
=
tmf
==
null
?
new
TrustManager
[]{
trustAllX509TrustManager
}
:
tmf
.
getTrustManagers
();
//不知道为啥双向不验服务器证书的时候TrustManager必须设置,但单向的直接null也可以不验。
sslContext
.
init
(
keyManagers
,
trustManagers
,
SecureRandom
.
getInstance
(
"SHA1PRNG"
));
ssLSocketFactoryMap
.
put
(
tag
,
sslContext
.
getSocketFactory
());
ifVerifyHostnameMap
.
put
(
tag
,
verifyHostname
);
log
.
info
(
"addSslConf succeed: ["
+
tag
+
"]"
+
(
tmf
==
null
?
",但没验服务器证书哦"
:
""
)
+
"。"
);
return
true
;
}
catch
(
Exception
e
)
{
log
.
error
(
"addSslConf fail. "
,
e
);
return
false
;
}
}
static
{
addSslConf
(
"uhttps"
,
null
,
null
,
null
,
null
,
false
);
}
private
static
KeyStore
loadKeyStore
(
String
path
,
String
pwd
,
String
type
)
{
FileInputStream
fis
=
null
;
try
{
KeyStore
ks
=
KeyStore
.
getInstance
(
type
);
fis
=
new
FileInputStream
(
path
);
char
[]
nPassword
=
null
;
nPassword
=
null
==
pwd
||
""
.
equals
(
pwd
.
trim
())
?
null
:
pwd
.
toCharArray
();
if
(
null
!=
ks
)
{
ks
.
load
(
fis
,
nPassword
);
}
return
ks
;
}
catch
(
Exception
e
)
{
log
.
error
(
"loadKeyStore Error"
,
e
);
}
finally
{
if
(
fis
!=
null
)
{
try
{
fis
.
close
();
}
catch
(
IOException
e
)
{
// e.printStackTrace();
}
}
}
return
null
;
}
public
static
void
main
(
String
[]
args
)
throws
UnsupportedEncodingException
,
NoSuchAlgorithmException
,
UnrecoverableKeyException
,
KeyStoreException
{
// HttpsUtil.addSslConf("cloudpos", "d:/certs/cloudpos/01003320-------001-----.jks", "000000", "d:/certs/cloudpos/trust.jks", "000000", false);
// for(int i=0;i<10000;i++){
// post("uhttps://gateway.test.95516.com/gateway/api/appTransReq.do", "accessType=0&bizType=000000&txnSubType=00&signature=ff3e9d82a5528ad51c5b3bde5fd2d62a8e016a68d28abb584140ad2d2baa2c2a&orderId=2019112215532700000154&reqReserved=%7Btestcase%3DTestCase_90_DF%7D&txnTime=20191122155327&txnType=00&merId=777290058110018&encoding=UTF-8&version=5.1.0&signMethod=12".getBytes());
// post("cloudpos://180.169.111.145:10009/CloudPosPayment/InsTransServlet", "{\"TrxIndCd\":\"SPK00461694051982042817\",\"TrxTp\":\"SPK004\",\"Version\":\"100\",\"FirmTermId\":\"52079000\",\"CerVer\":\"02\",\"FirmMchntId\":\"001332060120003\",\"EncryptData\":\"e8r/n/VkA1nQ+eOVRL5iHBwvgw0q/KYEyeARox+dtPFAKFsXmY064x6UU/pTBX3OLcA9PjEy3ATUmnxMwCb0GTRyn4Qh3OvotOh2YytbNt4g9gii5movpX04+eKCcbU2eIH5D4Bx+TTOv0t94LvMgf4FMN5djZ5XOjfnx9mpajrMKQEKBdwp97hOTv49QZJqW/AzMaagfErxBKqEeC+yG1pyvg23Xg+Scq/qheJ/w2XvCLKFoeZjKWN5bevpVkHS7KZdAqCx3T4wHEmZd0wo5YF3WdHwBT53LHZ6l6m0Ja6HpTxyaGccGULgcyhxxttWyqzoVKQCFU3ZlfX3b5Yxdg==\"}".getBytes());
// }
// addSslConf("test", null, null, null, null, true);
// post("test://gateway.test.95516.com/gateway/api/appTransReq.do", "accessType=0&bizType=000000&txnSubType=00&signature=ff3e9d82a5528ad51c5b3bde5fd2d62a8e016a68d28abb584140ad2d2baa2c2a&orderId=2019112215532700000154&reqReserved=%7Btestcase%3DTestCase_90_DF%7D&txnTime=20191122155327&txnType=00&merId=777290058110018&encoding=UTF-8&version=5.1.0&signMethod=12".getBytes());
}
}
liquidnet-bus-service/liquidnet-service-dragon/liquidnet-service-dragon-impl/src/main/java/com/liquidnet/service/dragon/channel/unionpay/sdk/QrcService.java
0 → 100644
View file @
70db7894
package
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.codec.binary.Base64
;
import
java.io.IOException
;
import
java.nio.charset.Charset
;
import
java.security.PublicKey
;
import
java.util.Map
;
import
static
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
SDKConstants
.*;
/**
* @ClassName QrcService
* @Description sdk接口服务类,接入商户集成请可以直接参考使用本类中的方法
* @date 2018-12-10 下午2:44:37
*/
@Slf4j
public
class
QrcService
{
/**
* 请求报文签名(使用配置文件中配置的私钥证书或者对称密钥签名)<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
)
{
return
signByCertInfo
(
reqData
,
SDKConfig
.
getConfig
().
getSignCertPath
(),
SDKConfig
.
getConfig
().
getSignCertPwd
(),
encoding
);
}
/**
* 多证书签名(通过传入私钥证书路径和密码签名)<br>
* 功能:如果有多个商户号接入银联,每个商户号对应不同的证书可以使用此方法:传入私钥证书和密码(并且在acp_sdk.properties中 配置 acpsdk.singleMode=false)<br>
* @param reqData 请求报文map<br>
* @param certPath 签名私钥文件(带路径)<br>
* @param certPwd 签名私钥密码<br>
* @param encoding 上送请求报文域encoding字段的值<br>
* @return 签名后的map对象<br>
*/
public
static
Map
<
String
,
String
>
signByCertInfo
(
Map
<
String
,
String
>
reqData
,
String
certPath
,
String
certPwd
,
String
encoding
)
{
Map
<
String
,
String
>
data
=
SDKUtil
.
filterBlank
(
reqData
);
if
(
SDKUtil
.
isEmpty
(
encoding
))
{
encoding
=
"UTF-8"
;
}
if
(
SDKUtil
.
isEmpty
(
certPath
)
||
SDKUtil
.
isEmpty
(
certPwd
))
{
log
.
error
(
"CertPath or CertPwd is empty"
);
return
data
;
}
String
signType
=
data
.
get
(
SDKConstants
.
param_signType
);
String
version
=
data
.
get
(
SDKConstants
.
param_version
);
String
reqType
=
data
.
get
(
SDKConstants
.
param_reqType
);
if
(
SDKUtil
.
isEmpty
(
signType
))
{
signType
=
QRC_SIGNTYPE_SHA1WITHRSA
;
}
try
{
if
(
VERSION_1_0_0
.
equals
(
version
))
{
//被扫脱机码两个接口无视配置固定按sha256withrsa处理。下面两个ifelse别改变顺序。
if
(
QRC_SIGNTYPE_SHA256WITHRSA
.
equals
(
signType
)
||
"0420000903"
.
equals
(
reqType
)
||
"0410000903"
.
equals
(
reqType
))
{
data
.
put
(
SDKConstants
.
param_certId
,
CertUtil
.
getCertIdByKeyStoreMap
(
certPath
,
certPwd
));
data
.
put
(
SDKConstants
.
param_signature
,
SDKUtil
.
signRsa2
(
data
,
certPath
,
certPwd
,
encoding
));
return
data
;
}
else
if
(
QRC_SIGNTYPE_SHA1WITHRSA
.
equals
(
signType
))
{
data
.
put
(
SDKConstants
.
param_certId
,
CertUtil
.
getCertIdByKeyStoreMap
(
certPath
,
certPwd
));
data
.
put
(
SDKConstants
.
param_signature
,
SDKUtil
.
signRsa
(
data
,
certPath
,
certPwd
,
encoding
));
return
data
;
}
else
if
(
QRC_SIGNTYPE_SM3WITHSM2
.
equals
(
signType
))
{
log
.
error
(
"国密算法按要求必须通过加密机签名,本sdk不提供。"
);
return
data
;
}
}
log
.
error
(
"未实现签名方法, version="
+
version
+
", signType="
+
signType
);
return
data
;
}
catch
(
Exception
e
)
{
log
.
error
(
"Sign Error"
,
e
);
return
data
;
}
}
/**
* 验证签名<br>
* @param resData 返回报文数据<br>
* @param encoding 上送请求报文域encoding字段的值<br>
* @return true 通过 false 未通过<br>
*/
public
static
boolean
validate
(
Map
<
String
,
String
>
resData
,
String
encoding
)
{
log
.
info
(
"验签处理开始"
);
if
(
SDKUtil
.
isEmpty
(
encoding
))
{
encoding
=
"UTF-8"
;
}
String
certId
=
resData
.
get
(
SDKConstants
.
param_certId
);
log
.
info
(
"对返回报文串验签使用的验签公钥序列号:["
+
certId
+
"]"
);
PublicKey
verifyKey
=
CertUtil
.
getValidatePublicKey
(
certId
);
if
(
verifyKey
==
null
)
{
log
.
error
(
"未找到此序列号证书。"
);
return
false
;
}
String
signType
=
resData
.
get
(
SDKConstants
.
param_signType
);
String
version
=
resData
.
get
(
SDKConstants
.
param_version
);
String
reqType
=
resData
.
get
(
SDKConstants
.
param_reqType
);
if
(
SDKUtil
.
isEmpty
(
signType
))
{
signType
=
QRC_SIGNTYPE_SHA1WITHRSA
;
}
try
{
if
(
VERSION_1_0_0
.
equals
(
version
))
{
//被扫脱机码两个接口无视配置固定按sha256withrsa处理。下面两个ifelse别改变顺序。
if
(
QRC_SIGNTYPE_SHA256WITHRSA
.
equals
(
signType
)
||
"0420000903"
.
equals
(
reqType
)
||
"0410000903"
.
equals
(
reqType
))
{
boolean
result
=
SDKUtil
.
verifyRsa2
(
resData
,
verifyKey
,
encoding
);
log
.
info
(
"验签"
+
(
result
?
"成功"
:
"失败"
)
+
"。"
);
return
result
;
}
else
if
(
QRC_SIGNTYPE_SHA1WITHRSA
.
equals
(
signType
))
{
boolean
result
=
SDKUtil
.
verifyRsa
(
resData
,
verifyKey
,
encoding
);
log
.
info
(
"验签"
+
(
result
?
"成功"
:
"失败"
)
+
"。"
);
return
result
;
}
else
if
(
QRC_SIGNTYPE_SM3WITHSM2
.
equals
(
signType
))
{
log
.
error
(
"国密算法按要求必须通过加密机签名,本sdk不提供。"
);
return
false
;
}
}
log
.
error
(
"未实现验签方法, version="
+
version
+
", signType="
+
signType
);
return
false
;
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
return
false
;
}
/**
* 密码加密并做base64<br>
* @param accNo 卡号<br>
* @param pin 密码<br>
* @param encoding<br>
* @return 加密的内容<br>
*/
public
static
String
encryptPin
(
String
accNo
,
String
pin
,
String
encoding
)
{
return
AcpService
.
encryptPin
(
accNo
,
pin
,
encoding
);
}
/**
* 敏感信息加密并做base64(卡号,手机号,cvn2,有效期)<br>
* @param data 送 phoneNo,cvn2,有效期<br>
* @param encoding<br>
* @return 加密的密文<br>
*/
public
static
String
encryptData
(
String
data
,
String
encoding
)
{
return
AcpService
.
encryptData
(
data
,
encoding
);
}
/**
* 敏感信息解密,使用配置文件acp_sdk.properties解密<br>
* @param base64EncryptedInfo 加密信息<br>
* @param encoding<br>
* @return 解密后的明文<br>
*/
public
static
String
decryptData
(
String
base64EncryptedInfo
,
String
encoding
)
{
return
AcpService
.
decryptData
(
base64EncryptedInfo
,
encoding
);
}
/**
* 敏感信息解密,通过传入的私钥解密<br>
* @param base64EncryptedInfo 加密信息<br>
* @param certPath 私钥文件(带全路径)<br>
* @param certPwd 私钥密码<br>
* @param encoding<br>
* @return
*/
public
static
String
decryptData
(
String
base64EncryptedInfo
,
String
certPath
,
String
certPwd
,
String
encoding
)
{
return
AcpService
.
decryptData
(
base64EncryptedInfo
,
certPath
,
certPwd
,
encoding
);
}
/**
* 获取敏感信息加密证书的物理序列号<br>
* @return
*/
public
static
String
getEncryptCertId
(){
return
CertUtil
.
getEncryptCert
().
certId
;
}
/**
* 功能:后台交易提交请求报文并接收同步应答报文<br>
* @param reqData 请求报文<br>
* @param reqUrl 请求地址<br>
* @param encoding<br>
* @return 应答http 200返回true ,其他false<br>
*/
public
static
Map
<
String
,
String
>
post
(
Map
<
String
,
String
>
reqData
,
String
reqUrl
,
String
encoding
)
{
return
AcpService
.
post
(
reqData
,
reqUrl
,
encoding
);
}
/**
* base64({a=b&c=d})
* @param map
* @param encoding
* @return
*/
public
static
String
getKVBase64Field
(
Map
<
String
,
String
>
map
,
String
encoding
){
StringBuffer
sf
=
new
StringBuffer
();
String
info
=
sf
.
append
(
SDKConstants
.
LEFT_BRACE
)
.
append
(
SDKUtil
.
createLinkString
(
map
,
false
,
false
,
encoding
))
.
append
(
SDKConstants
.
RIGHT_BRACE
).
toString
();
return
Base64
.
encodeBase64String
(
info
.
getBytes
(
Charset
.
forName
(
encoding
)));
}
/**
* base64(rsa({a=b&c=d}))
* @param map
* @param encoding
* @return
*/
public
static
String
getKVEncBase64Field
(
Map
<
String
,
String
>
map
,
String
encoding
){
StringBuffer
sf
=
new
StringBuffer
();
String
info
=
sf
.
append
(
SDKConstants
.
LEFT_BRACE
)
.
append
(
SDKUtil
.
createLinkString
(
map
,
false
,
false
,
encoding
))
.
append
(
SDKConstants
.
RIGHT_BRACE
).
toString
();
return
QrcService
.
encryptData
(
info
,
encoding
);
}
/**
* base64({a=b&c=d})
* 解析返回报文的payerInfo域,敏感信息不加密时使用:<br>
* @param base64data<br>
* @param encoding<br>
* @return
*/
public
static
Map
<
String
,
String
>
parseKVBase64Field
(
String
base64data
,
String
encoding
){
String
data
=
new
String
(
Base64
.
decodeBase64
(
base64data
),
Charset
.
forName
(
encoding
));
data
=
data
.
substring
(
1
,
data
.
length
()
-
1
);
return
SDKUtil
.
parseRespString
(
data
);
}
/**
* base64(rsa({a=b&c=d}))
* 解析返回报文的payerInfo域,敏感信息加密时使用:<br>
* @param base64data<br>
* @param encoding<br>
* @return
*/
public
static
Map
<
String
,
String
>
parseKVEncBase64Field
(
String
base64data
,
String
encoding
){
String
data
=
QrcService
.
decryptData
(
base64data
,
encoding
);
data
=
data
.
substring
(
1
,
data
.
length
()
-
1
);
return
SDKUtil
.
parseRespString
(
data
);
}
/**
* base64(rsa({a=b&c=d}))
* 解析返回报文中的payerInfo域,敏感信息加密时使用,多证书方式。<br>
* @param base64data<br>
* @param encoding<br>
* @return
*/
public
static
Map
<
String
,
String
>
parseKVEncBase64Field
(
String
base64data
,
String
certPath
,
String
certPwd
,
String
encoding
){
String
data
=
QrcService
.
decryptData
(
base64data
,
certPath
,
certPwd
,
encoding
);
data
=
data
.
substring
(
1
,
data
.
length
()
-
1
);
return
SDKUtil
.
parseRespString
(
data
);
}
/**
* 对字符串做base64<br>
* @param rawStr<br>
* @param encoding<br>
* @return<br>
* @throws IOException
*/
public
static
String
base64Encode
(
String
rawStr
,
String
encoding
){
return
AcpService
.
base64Encode
(
rawStr
,
encoding
);
}
/**
* 对字符串做base64<br>
* @param base64Str<br>
* @param encoding<br>
* @return<br>
* @throws IOException
*/
public
static
String
base64Decode
(
String
base64Str
,
String
encoding
){
return
AcpService
.
base64Decode
(
base64Str
,
encoding
);
}
/**
* luhn算法
*
* @param number
* @return
*/
public
static
int
genLuhn
(
String
number
)
{
number
=
number
+
"0"
;
int
s1
=
0
,
s2
=
0
;
String
reverse
=
new
StringBuffer
(
number
).
reverse
().
toString
();
for
(
int
i
=
0
;
i
<
reverse
.
length
();
i
++)
{
int
digit
=
Character
.
digit
(
reverse
.
charAt
(
i
),
10
);
if
(
i
%
2
==
0
)
{
// this is for odd digits, they are 1-indexed in //
// the algorithm
s1
+=
digit
;
}
else
{
// add 2 * digit for 0-4, add 2 * digit - 9 for 5-9
s2
+=
2
*
digit
;
if
(
digit
>=
5
)
{
s2
-=
9
;
}
}
}
int
check
=
10
-
((
s1
+
s2
)
%
10
);
if
(
check
==
10
)
check
=
0
;
return
check
;
}
}
liquidnet-bus-service/liquidnet-service-dragon/liquidnet-service-dragon-impl/src/main/java/com/liquidnet/service/dragon/channel/unionpay/sdk/SDKConfig.java
0 → 100644
View file @
70db7894
/**
*
* Licensed Property to China UnionPay Co., Ltd.
*
* (C) Copyright of China UnionPay Co., Ltd. 2010
* All Rights Reserved.
*
*
* Modification History:
* =============================================================================
* Author Date Description
* ------------ ---------- ---------------------------------------------------
* xshu 2014-05-28 MPI基本参数工具类
* =============================================================================
*/
package
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
;
import
lombok.extern.slf4j.Slf4j
;
import
java.io.*
;
import
java.util.Properties
;
/**
*
* @ClassName SDKConfig
* @Description acpsdk配置文件acp_sdk.properties配置信息类
* @date 2016-7-22 下午4:04:55
*/
@Slf4j
public
class
SDKConfig
{
public
static
final
String
FILE_NAME
=
"acp_sdk.properties"
;
/** 前台请求URL. */
private
String
frontRequestUrl
;
/** 后台请求URL. */
private
String
backRequestUrl
;
/** 二维码统一下单请求URL. */
private
String
orderRequestUrl
;
/** 单笔查询 */
private
String
singleQueryUrl
;
/** 批量查询 */
private
String
batchQueryUrl
;
/** 批量交易 */
private
String
batchTransUrl
;
/** 文件传输 */
private
String
fileTransUrl
;
/** 签名证书路径. */
private
String
signCertPath
;
/** 签名证书密码. */
private
String
signCertPwd
;
/** 签名证书类型. */
private
String
signCertType
;
/** 加密公钥证书路径. */
private
String
encryptCertPath
;
/** 验证签名公钥证书目录. */
private
String
validateCertDir
;
/** 按照商户代码读取指定签名证书目录. */
private
String
signCertDir
;
// /** 磁道加密证书路径. */
// private String encryptTrackCertPath;
/** 磁道加密公钥模数. */
private
String
encryptTrackKeyModulus
;
/** 磁道加密公钥指数. */
private
String
encryptTrackKeyExponent
;
/** 6.0.0统一支付产品加密pin公钥证书路径. */
private
String
pinEncryptCertPath
;
/** 有卡交易. */
private
String
cardRequestUrl
;
/** app交易 */
private
String
appRequestUrl
;
/** 证书使用模式(单证书/多证书) */
private
String
singleMode
;
/** 安全密钥(SHA256和SM3计算时使用) */
private
String
secureKey
;
/** 中级证书路径 */
private
String
middleCertPath
;
/** 根证书路径 */
private
String
rootCertPath
;
/** 是否验证验签证书CN,除了false都验 */
private
boolean
ifValidateCNName
=
true
;
/** 是否验证https证书,默认都不验 */
private
boolean
ifValidateRemoteCert
=
false
;
/** signMethod,没配按01吧 */
private
String
signMethod
=
"01"
;
/** version,没配按5.0.0 */
private
String
version
=
"5.0.0"
;
/** frontUrl */
private
String
frontUrl
;
/** backUrl */
private
String
backUrl
;
/** frontFailUrl */
private
String
frontFailUrl
;
/*缴费相关地址*/
private
String
jfFrontRequestUrl
;
private
String
jfBackRequestUrl
;
private
String
jfSingleQueryUrl
;
private
String
jfCardRequestUrl
;
private
String
jfAppRequestUrl
;
//二维码
private
String
qrcBackTransUrl
;
private
String
qrcB2cIssBackTransUrl
;
private
String
qrcB2cMerBackTransUrl
;
private
String
qrcB2cMerBackSynTransUrl
;
//综合认证
private
String
zhrzFrontRequestUrl
;
private
String
zhrzBackRequestUrl
;
private
String
zhrzSingleQueryUrl
;
private
String
zhrzCardRequestUrl
;
private
String
zhrzAppRequestUrl
;
private
String
zhrzFaceRequestUrl
;
/** acp6 */
private
String
transUrl
;
/** 配置文件中的前台URL常量. */
public
static
final
String
SDK_FRONT_URL
=
"acpsdk.frontTransUrl"
;
/** 配置文件中的后台URL常量. */
public
static
final
String
SDK_BACK_URL
=
"acpsdk.backTransUrl"
;
/** 配置文件中的统一下单URL常量. */
public
static
final
String
SDK_ORDER_URL
=
"acpsdk.orderTransUrl"
;
/** 配置文件中的单笔交易查询URL常量. */
public
static
final
String
SDK_SIGNQ_URL
=
"acpsdk.singleQueryUrl"
;
/** 配置文件中的批量交易查询URL常量. */
public
static
final
String
SDK_BATQ_URL
=
"acpsdk.batchQueryUrl"
;
/** 配置文件中的批量交易URL常量. */
public
static
final
String
SDK_BATTRANS_URL
=
"acpsdk.batchTransUrl"
;
/** 配置文件中的文件类交易URL常量. */
public
static
final
String
SDK_FILETRANS_URL
=
"acpsdk.fileTransUrl"
;
/** 配置文件中的有卡交易URL常量. */
public
static
final
String
SDK_CARD_URL
=
"acpsdk.cardTransUrl"
;
/** 配置文件中的app交易URL常量. */
public
static
final
String
SDK_APP_URL
=
"acpsdk.appTransUrl"
;
/** 以下缴费产品使用,其余产品用不到,无视即可 */
// 前台请求地址
public
static
final
String
JF_SDK_FRONT_TRANS_URL
=
"acpsdk.jfFrontTransUrl"
;
// 后台请求地址
public
static
final
String
JF_SDK_BACK_TRANS_URL
=
"acpsdk.jfBackTransUrl"
;
// 单笔查询请求地址
public
static
final
String
JF_SDK_SINGLE_QUERY_URL
=
"acpsdk.jfSingleQueryUrl"
;
// 有卡交易地址
public
static
final
String
JF_SDK_CARD_TRANS_URL
=
"acpsdk.jfCardTransUrl"
;
// App交易地址
public
static
final
String
JF_SDK_APP_TRANS_URL
=
"acpsdk.jfAppTransUrl"
;
// 人到人
public
static
final
String
QRC_BACK_TRANS_URL
=
"acpsdk.qrcBackTransUrl"
;
// 人到人
public
static
final
String
QRC_B2C_ISS_BACK_TRANS_URL
=
"acpsdk.qrcB2cIssBackTransUrl"
;
// 人到人
public
static
final
String
QRC_B2C_MER_BACK_TRANS_URL
=
"acpsdk.qrcB2cMerBackTransUrl"
;
public
static
final
String
QRC_B2C_MER_BACK_SYN_TRANS_URL
=
"acpsdk.qrcB2cMerBackSynTransUrl"
;
/** 以下综合认证产品使用,其余产品用不到,无视即可 */
// 前台请求地址
public
static
final
String
ZHRZ_SDK_FRONT_TRANS_URL
=
"acpsdk.zhrzFrontTransUrl"
;
// 后台请求地址
public
static
final
String
ZHRZ_SDK_BACK_TRANS_URL
=
"acpsdk.zhrzBackTransUrl"
;
// 单笔查询请求地址
public
static
final
String
ZHRZ_SDK_SINGLE_QUERY_URL
=
"acpsdk.zhrzSingleQueryUrl"
;
// 有卡交易地址
public
static
final
String
ZHRZ_SDK_CARD_TRANS_URL
=
"acpsdk.zhrzCardTransUrl"
;
// App交易地址
public
static
final
String
ZHRZ_SDK_APP_TRANS_URL
=
"acpsdk.zhrzAppTransUrl"
;
// 图片识别交易地址
public
static
final
String
ZHRZ_SDK_FACE_TRANS_URL
=
"acpsdk.zhrzFaceTransUrl"
;
// acp6
public
static
final
String
TRANS_URL
=
"acpsdk.transUrl"
;
/** 配置文件中签名证书路径常量. */
public
static
final
String
SDK_SIGNCERT_PATH
=
"acpsdk.signCert.path"
;
/** 配置文件中签名证书密码常量. */
public
static
final
String
SDK_SIGNCERT_PWD
=
"acpsdk.signCert.pwd"
;
/** 配置文件中签名证书类型常量. */
public
static
final
String
SDK_SIGNCERT_TYPE
=
"acpsdk.signCert.type"
;
/** 配置文件中加密证书路径常量. */
public
static
final
String
SDK_ENCRYPTCERT_PATH
=
"acpsdk.encryptCert.path"
;
// /** 配置文件中磁道加密证书路径常量. */
// public static final String SDK_ENCRYPTTRACKCERT_PATH = "acpsdk.encryptTrackCert.path";
/** 配置文件中5.0.0有卡产品磁道加密公钥模数常量. */
public
static
final
String
SDK_ENCRYPTTRACKKEY_MODULUS
=
"acpsdk.encryptTrackKey.modulus"
;
/** 配置文件中5.0.0有卡产品磁道加密公钥指数常量. */
public
static
final
String
SDK_ENCRYPTTRACKKEY_EXPONENT
=
"acpsdk.encryptTrackKey.exponent"
;
/** 配置文件中验证签名证书目录常量. */
public
static
final
String
SDK_VALIDATECERT_DIR
=
"acpsdk.validateCert.dir"
;
/** 配置文件中6.0.0统一支付产品加密pin证书路径常量. */
public
static
final
String
SDK_PINENCRYPTCERT_PATH
=
"acpsdk.pinEncryptCert.path"
;
/** 配置文件中是否加密cvn2常量. */
public
static
final
String
SDK_CVN_ENC
=
"acpsdk.cvn2.enc"
;
/** 配置文件中是否加密cvn2有效期常量. */
public
static
final
String
SDK_DATE_ENC
=
"acpsdk.date.enc"
;
/** 配置文件中是否加密卡号常量. */
public
static
final
String
SDK_PAN_ENC
=
"acpsdk.pan.enc"
;
/** 配置文件中证书使用模式 */
public
static
final
String
SDK_SINGLEMODE
=
"acpsdk.singleMode"
;
/** 配置文件中安全密钥 */
public
static
final
String
SDK_SECURITYKEY
=
"acpsdk.secureKey"
;
/** 配置文件中根证书路径常量 */
public
static
final
String
SDK_ROOTCERT_PATH
=
"acpsdk.rootCert.path"
;
/** 配置文件中根证书路径常量 */
public
static
final
String
SDK_MIDDLECERT_PATH
=
"acpsdk.middleCert.path"
;
/** 配置是否需要验证验签证书CN,除了false之外的值都当true处理 */
public
static
final
String
SDK_IF_VALIDATE_CN_NAME
=
"acpsdk.ifValidateCNName"
;
/** 配置是否需要验证https证书,除了true之外的值都当false处理 */
public
static
final
String
SDK_IF_VALIDATE_REMOTE_CERT
=
"acpsdk.ifValidateRemoteCert"
;
/** signmethod */
public
static
final
String
SDK_SIGN_METHOD
=
"acpsdk.signMethod"
;
/** version */
public
static
final
String
SDK_VERSION
=
"acpsdk.version"
;
/** 后台通知地址 */
public
static
final
String
SDK_BACKURL
=
"acpsdk.backUrl"
;
/** 前台通知地址 */
public
static
final
String
SDK_FRONTURL
=
"acpsdk.frontUrl"
;
/** 前台失败通知地址 */
public
static
final
String
SDK_FRONT_FAIL_URL
=
"acpsdk.frontFailUrl"
;
/** 操作对象. */
private
static
SDKConfig
config
=
null
;
/** 属性文件对象. */
protected
Properties
properties
;
protected
SDKConfig
()
{
super
();
}
/**
* 获取config对象.
* @return
*/
public
static
SDKConfig
getConfig
()
{
if
(
config
==
null
)
{
log
.
warn
(
"未主动调用loadPropertiesFromSrc或loadPropertiesFromPath方法,默认调loadPropertiesFromSrc初始化"
);
SDKConfig
.
loadPropertiesFromSrc
();
}
if
(
config
==
null
)
{
log
.
error
(
"初始化失败"
);
config
=
new
SDKConfig
();
}
return
config
;
}
/**
* 从properties文件加载
*
* @param rootPath
* 不包含文件名的目录.
*/
public
static
void
loadPropertiesFromPath
(
String
rootPath
)
{
Properties
properties
=
getPropertiesFromPath
(
rootPath
);
loadProperties
(
properties
);
}
protected
static
Properties
getPropertiesFromSrc
()
{
InputStream
in
=
null
;
try
{
log
.
info
(
"从classpath: "
+
SDKConfig
.
class
.
getClassLoader
().
getResource
(
""
).
getPath
()+
" 获取属性文件"
+
FILE_NAME
);
in
=
SDKConfig
.
class
.
getClassLoader
().
getResourceAsStream
(
FILE_NAME
);
if
(
in
==
null
)
{
log
.
error
(
FILE_NAME
+
"属性文件未能在classpath指定的目录下 "
+
SDKConfig
.
class
.
getClassLoader
().
getResource
(
""
).
getPath
()+
" 找到!"
);
return
null
;
}
Properties
properties
=
new
Properties
();
properties
.
load
(
in
);
return
properties
;
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
finally
{
if
(
in
!=
null
)
{
try
{
in
.
close
();
}
catch
(
IOException
e
)
{
}
}
}
return
null
;
}
protected
static
Properties
getPropertiesFromPath
(
String
rootPath
)
{
if
(
rootPath
==
null
||
""
.
equals
(
rootPath
.
trim
()))
{
log
.
error
(
"rootPath为空"
);
return
null
;
}
String
path
=
rootPath
+
File
.
separator
+
FILE_NAME
;
log
.
info
(
"从路径读取配置文件: "
+
path
);
File
file
=
new
File
(
path
);
InputStream
in
=
null
;
if
(!
file
.
exists
())
{
log
.
error
(
rootPath
+
"不存在"
+
FILE_NAME
);
return
null
;
}
try
{
in
=
new
FileInputStream
(
file
);
Properties
properties
=
new
Properties
();
properties
.
load
(
in
);
return
properties
;
}
catch
(
FileNotFoundException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
catch
(
IOException
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
}
finally
{
if
(
in
!=
null
)
{
try
{
in
.
close
();
}
catch
(
IOException
e
)
{
}
}
}
return
null
;
}
/**
* 从classpath路径下加载配置参数
*/
public
static
void
loadPropertiesFromSrc
()
{
Properties
properties
=
getPropertiesFromSrc
();
loadProperties
(
properties
);
}
/**
* 根据传入的 {@link Properties}对象设置配置参数
*
* @param pro
*/
public
static
void
loadProperties
(
Properties
pro
)
{
config
=
new
SDKConfig
();
config
.
loadProperties1
(
pro
);
}
/**
* 根据传入的 {@link Properties}对象设置配置参数
*
* @param pro
*/
protected
void
loadProperties1
(
Properties
pro
)
{
if
(
pro
==
null
)
{
log
.
error
(
"loadProperties input is null"
);
return
;
}
if
(
this
.
properties
==
null
)
{
this
.
properties
=
pro
;
}
log
.
info
(
"开始从属性文件中加载配置项"
);
String
value
=
null
;
value
=
pro
.
getProperty
(
SDK_SIGNCERT_PATH
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
signCertPath
=
value
.
trim
();
log
.
info
(
"配置项:私钥签名证书路径==>"
+
SDK_SIGNCERT_PATH
+
"==>"
+
value
+
" 已加载"
);
}
value
=
pro
.
getProperty
(
SDK_SIGNCERT_PWD
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
signCertPwd
=
value
.
trim
();
log
.
info
(
"配置项:私钥签名证书密码==>"
+
SDK_SIGNCERT_PWD
+
" 已加载"
);
}
value
=
pro
.
getProperty
(
SDK_SIGNCERT_TYPE
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
signCertType
=
value
.
trim
();
log
.
info
(
"配置项:私钥签名证书类型==>"
+
SDK_SIGNCERT_TYPE
+
"==>"
+
value
+
" 已加载"
);
}
value
=
pro
.
getProperty
(
SDK_ENCRYPTCERT_PATH
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
encryptCertPath
=
value
.
trim
();
log
.
info
(
"配置项:敏感信息加密证书==>"
+
SDK_ENCRYPTCERT_PATH
+
"==>"
+
value
+
" 已加载"
);
}
value
=
pro
.
getProperty
(
SDK_VALIDATECERT_DIR
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
validateCertDir
=
value
.
trim
();
log
.
info
(
"配置项:验证签名证书路径(这里配置的是目录,不要指定到公钥文件)==>"
+
SDK_VALIDATECERT_DIR
+
"==>"
+
value
+
" 已加载"
);
}
value
=
pro
.
getProperty
(
SDK_PINENCRYPTCERT_PATH
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
pinEncryptCertPath
=
value
.
trim
();
log
.
info
(
"配置项:6.0.0统一支付产品加密pin证书路径(这里配置的是目录,不要指定到公钥文件)==>"
+
SDK_PINENCRYPTCERT_PATH
+
"==>"
+
value
+
" 已加载"
);
}
value
=
pro
.
getProperty
(
SDK_FRONT_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
frontRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_BACK_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
backRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_ORDER_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
orderRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_BATQ_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
batchQueryUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_BATTRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
batchTransUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_FILETRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
fileTransUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_SIGNQ_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
singleQueryUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_CARD_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
cardRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_APP_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
appRequestUrl
=
value
.
trim
();
}
// value = pro.getProperty(SDK_ENCRYPTTRACKCERT_PATH);
// if (!SDKUtil.isEmpty(value)) {
// this.encryptTrackCertPath = value.trim();
// }
value
=
pro
.
getProperty
(
SDK_SECURITYKEY
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
secureKey
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_ROOTCERT_PATH
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
rootCertPath
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_MIDDLECERT_PATH
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
middleCertPath
=
value
.
trim
();
}
/**缴费部分**/
value
=
pro
.
getProperty
(
JF_SDK_FRONT_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
jfFrontRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
JF_SDK_BACK_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
jfBackRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
JF_SDK_SINGLE_QUERY_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
jfSingleQueryUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
JF_SDK_CARD_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
jfCardRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
JF_SDK_APP_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
jfAppRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
QRC_BACK_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
qrcBackTransUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
QRC_B2C_ISS_BACK_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
qrcB2cIssBackTransUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
QRC_B2C_MER_BACK_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
qrcB2cMerBackTransUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
QRC_B2C_MER_BACK_SYN_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
qrcB2cMerBackSynTransUrl
=
value
.
trim
();
}
/**综合认证**/
value
=
pro
.
getProperty
(
ZHRZ_SDK_FRONT_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
zhrzFrontRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
ZHRZ_SDK_BACK_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
zhrzBackRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
ZHRZ_SDK_SINGLE_QUERY_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
zhrzSingleQueryUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
ZHRZ_SDK_CARD_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
zhrzCardRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
ZHRZ_SDK_APP_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
zhrzAppRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
ZHRZ_SDK_FACE_TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
zhrzFaceRequestUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
TRANS_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
transUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_ENCRYPTTRACKKEY_EXPONENT
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
encryptTrackKeyExponent
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_ENCRYPTTRACKKEY_MODULUS
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
encryptTrackKeyModulus
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_IF_VALIDATE_CN_NAME
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
if
(
SDKConstants
.
FALSE_STRING
.
equals
(
value
.
trim
()))
this
.
ifValidateCNName
=
false
;
}
value
=
pro
.
getProperty
(
SDK_IF_VALIDATE_REMOTE_CERT
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
if
(
SDKConstants
.
TRUE_STRING
.
equals
(
value
.
trim
()))
this
.
ifValidateRemoteCert
=
true
;
}
value
=
pro
.
getProperty
(
SDK_SIGN_METHOD
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
signMethod
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_SIGN_METHOD
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
signMethod
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_VERSION
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
version
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_FRONTURL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
frontUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_BACKURL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
backUrl
=
value
.
trim
();
}
value
=
pro
.
getProperty
(
SDK_FRONT_FAIL_URL
);
if
(!
SDKUtil
.
isEmpty
(
value
))
{
this
.
frontFailUrl
=
value
.
trim
();
}
}
public
String
getFrontRequestUrl
()
{
return
frontRequestUrl
;
}
public
String
getBackRequestUrl
()
{
return
backRequestUrl
;
}
public
String
getOrderRequestUrl
()
{
return
orderRequestUrl
;
}
public
String
getSignCertPath
()
{
return
signCertPath
;
}
public
String
getSignCertPwd
()
{
return
signCertPwd
;
}
public
String
getSignCertType
()
{
return
signCertType
;
}
public
String
getEncryptCertPath
()
{
return
encryptCertPath
;
}
public
String
getValidateCertDir
()
{
return
validateCertDir
;
}
public
String
getSingleQueryUrl
()
{
return
singleQueryUrl
;
}
public
String
getBatchQueryUrl
()
{
return
batchQueryUrl
;
}
public
String
getBatchTransUrl
()
{
return
batchTransUrl
;
}
public
String
getFileTransUrl
()
{
return
fileTransUrl
;
}
public
String
getSignCertDir
()
{
return
signCertDir
;
}
public
Properties
getProperties
()
{
return
properties
;
}
public
String
getCardRequestUrl
()
{
return
cardRequestUrl
;
}
public
String
getAppRequestUrl
()
{
return
appRequestUrl
;
}
// public String getEncryptTrackCertPath() {
// return encryptTrackCertPath;
// }
public
String
getPinEncryptCertPath
()
{
return
pinEncryptCertPath
;
}
public
String
getJfFrontRequestUrl
()
{
return
jfFrontRequestUrl
;
}
public
String
getJfBackRequestUrl
()
{
return
jfBackRequestUrl
;
}
public
String
getJfSingleQueryUrl
()
{
return
jfSingleQueryUrl
;
}
public
String
getJfCardRequestUrl
()
{
return
jfCardRequestUrl
;
}
public
String
getJfAppRequestUrl
()
{
return
jfAppRequestUrl
;
}
public
String
getSingleMode
()
{
return
singleMode
;
}
public
String
getEncryptTrackKeyExponent
()
{
return
encryptTrackKeyExponent
;
}
public
String
getEncryptTrackKeyModulus
()
{
return
encryptTrackKeyModulus
;
}
public
String
getSecureKey
()
{
return
secureKey
;
}
public
String
getMiddleCertPath
()
{
return
middleCertPath
;
}
public
boolean
isIfValidateCNName
()
{
return
ifValidateCNName
;
}
public
boolean
isIfValidateRemoteCert
()
{
return
ifValidateRemoteCert
;
}
public
String
getSignMethod
()
{
return
signMethod
;
}
public
String
getQrcBackTransUrl
()
{
return
qrcBackTransUrl
;
}
public
String
getQrcB2cIssBackTransUrl
()
{
return
qrcB2cIssBackTransUrl
;
}
public
String
getQrcB2cMerBackTransUrl
()
{
return
qrcB2cMerBackTransUrl
;
}
public
String
getQrcB2cMerBackSynTransUrl
()
{
return
qrcB2cMerBackSynTransUrl
;
}
public
String
getZhrzFrontRequestUrl
()
{
return
zhrzFrontRequestUrl
;
}
public
String
getZhrzBackRequestUrl
()
{
return
zhrzBackRequestUrl
;
}
public
String
getZhrzSingleQueryUrl
()
{
return
zhrzSingleQueryUrl
;
}
public
String
getZhrzCardRequestUrl
()
{
return
zhrzCardRequestUrl
;
}
public
String
getZhrzAppRequestUrl
()
{
return
zhrzAppRequestUrl
;
}
public
String
getZhrzFaceRequestUrl
()
{
return
zhrzFaceRequestUrl
;
}
public
String
getVersion
()
{
return
version
;
}
public
String
getFrontUrl
()
{
return
frontUrl
;
}
public
String
getBackUrl
()
{
return
backUrl
;
}
public
String
getFrontFailUrl
()
{
return
frontFailUrl
;
}
public
String
getRootCertPath
()
{
return
rootCertPath
;
}
public
String
getTransUrl
()
{
return
transUrl
;
}
}
liquidnet-bus-service/liquidnet-service-dragon/liquidnet-service-dragon-impl/src/main/java/com/liquidnet/service/dragon/channel/unionpay/sdk/SDKConstants.java
0 → 100644
View file @
70db7894
/**
*
* Licensed Property to China UnionPay Co., Ltd.
*
* (C) Copyright of China UnionPay Co., Ltd. 2010
* All Rights Reserved.
*
*
* Modification History:
* =============================================================================
* Author Date Description
* ------------ ---------- ---------------------------------------------------
* xshu 2014-05-28 MPI插件包常量定义
* =============================================================================
*/
package
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
;
/**
*
* @ClassName SDKConstants
* @Description acpsdk常量类
* @date 2016-7-22 下午4:05:54
*/
public
class
SDKConstants
{
public
final
static
String
COLUMN_DEFAULT
=
"-"
;
public
final
static
String
KEY_DELIMITER
=
"#"
;
/** memeber variable: blank. */
public
static
final
String
BLANK
=
""
;
/** member variabel: space. */
public
static
final
String
SPACE
=
" "
;
/** memeber variable: unline. */
public
static
final
String
UNLINE
=
"_"
;
/** memeber varibale: star. */
public
static
final
String
STAR
=
"*"
;
/** memeber variable: line. */
public
static
final
String
LINE
=
"-"
;
/** memeber variable: add. */
public
static
final
String
ADD
=
"+"
;
/** memeber variable: colon. */
public
final
static
String
COLON
=
"|"
;
/** memeber variable: point. */
public
final
static
String
POINT
=
"."
;
/** memeber variable: comma. */
public
final
static
String
COMMA
=
","
;
/** memeber variable: slash. */
public
final
static
String
SLASH
=
"/"
;
/** memeber variable: div. */
public
final
static
String
DIV
=
"/"
;
/** memeber variable: left . */
public
final
static
String
LB
=
"("
;
/** memeber variable: right. */
public
final
static
String
RB
=
")"
;
/** memeber variable: rmb. */
public
final
static
String
CUR_RMB
=
"RMB"
;
/** memeber variable: .page size */
public
static
final
int
PAGE_SIZE
=
10
;
/** memeber variable: String ONE. */
public
static
final
String
ONE
=
"1"
;
/** memeber variable: String ZERO. */
public
static
final
String
ZERO
=
"0"
;
/** memeber variable: number six. */
public
static
final
int
NUM_SIX
=
6
;
/** memeber variable: equal mark. */
public
static
final
String
EQUAL
=
"="
;
/** memeber variable: operation ne. */
public
static
final
String
NE
=
"!="
;
/** memeber variable: operation le. */
public
static
final
String
LE
=
"<="
;
/** memeber variable: operation ge. */
public
static
final
String
GE
=
">="
;
/** memeber variable: operation lt. */
public
static
final
String
LT
=
"<"
;
/** memeber variable: operation gt. */
public
static
final
String
GT
=
">"
;
/** memeber variable: list separator. */
public
static
final
String
SEP
=
"./"
;
/** memeber variable: Y. */
public
static
final
String
Y
=
"Y"
;
/** memeber variable: AMPERSAND. */
public
static
final
String
AMPERSAND
=
"&"
;
/** memeber variable: SQL_LIKE_TAG. */
public
static
final
String
SQL_LIKE_TAG
=
"%"
;
/** memeber variable: @. */
public
static
final
String
MAIL
=
"@"
;
/** memeber variable: number zero. */
public
static
final
int
NZERO
=
0
;
public
static
final
String
LEFT_BRACE
=
"{"
;
public
static
final
String
RIGHT_BRACE
=
"}"
;
/** memeber variable: string true. */
public
static
final
String
TRUE_STRING
=
"true"
;
/** memeber variable: string false. */
public
static
final
String
FALSE_STRING
=
"false"
;
/** memeber variable: forward success. */
public
static
final
String
SUCCESS
=
"success"
;
/** memeber variable: forward fail. */
public
static
final
String
FAIL
=
"fail"
;
/** memeber variable: global forward success. */
public
static
final
String
GLOBAL_SUCCESS
=
"$success"
;
/** memeber variable: global forward fail. */
public
static
final
String
GLOBAL_FAIL
=
"$fail"
;
public
static
final
String
UTF_8_ENCODING
=
"UTF-8"
;
public
static
final
String
GBK_ENCODING
=
"GBK"
;
public
static
final
String
CONTENT_TYPE
=
"Content-type"
;
public
static
final
String
APP_XML_TYPE
=
"application/xml;charset=utf-8"
;
public
static
final
String
APP_FORM_TYPE
=
"application/x-www-form-urlencoded;charset="
;
public
static
final
String
VERSION_1_0_0
=
"1.0.0"
;
public
static
final
String
VERSION_5_0_0
=
"5.0.0"
;
public
static
final
String
VERSION_5_0_1
=
"5.0.1"
;
public
static
final
String
VERSION_5_1_0
=
"5.1.0"
;
public
static
final
String
VERSION_6_0_0
=
"6.0.0"
;
public
static
final
String
SIGNMETHOD_RSA
=
"01"
;
public
static
final
String
SIGNMETHOD_SHA256
=
"11"
;
public
static
final
String
SIGNMETHOD_SM3
=
"12"
;
public
static
final
String
SIGNMETHOD6_RSA_SHA256
=
"RSA-SHA256"
;
public
static
final
String
UNIONPAY_CNNAME
=
"中国银联股份有限公司"
;
public
static
final
String
QRC_SIGNTYPE_SHA1WITHRSA
=
"01"
;
public
static
final
String
QRC_SIGNTYPE_SHA256WITHRSA
=
"02"
;
public
static
final
String
QRC_SIGNTYPE_SM3WITHSM2
=
"03"
;
public
static
final
String
CERTTYPE_01
=
"01"
;
// 敏感信息加密公钥
public
static
final
String
CERTTYPE_02
=
"02"
;
// 磁道加密公钥
/******************************************** 5.0报文接口定义 ********************************************/
/** 版本号. */
public
static
final
String
param_version
=
"version"
;
/** 证书ID. */
public
static
final
String
param_certId
=
"certId"
;
/** 签名. */
public
static
final
String
param_signature
=
"signature"
;
/** 签名方法. */
public
static
final
String
param_signMethod
=
"signMethod"
;
/** 编码方式. */
public
static
final
String
param_encoding
=
"encoding"
;
/** 交易类型. */
public
static
final
String
param_txnType
=
"txnType"
;
/** 交易子类. */
public
static
final
String
param_txnSubType
=
"txnSubType"
;
/** 业务类型. */
public
static
final
String
param_bizType
=
"bizType"
;
/** 前台通知地址 . */
public
static
final
String
param_frontUrl
=
"frontUrl"
;
/** 后台通知地址. */
public
static
final
String
param_backUrl
=
"backUrl"
;
/** 接入类型. */
public
static
final
String
param_accessType
=
"accessType"
;
/** 收单机构代码. */
public
static
final
String
param_acqInsCode
=
"acqInsCode"
;
/** 商户类别. */
public
static
final
String
param_merCatCode
=
"merCatCode"
;
/** 商户类型. */
public
static
final
String
param_merType
=
"merType"
;
/** 商户代码. */
public
static
final
String
param_merId
=
"merId"
;
/** 商户名称. */
public
static
final
String
param_merName
=
"merName"
;
/** 商户简称. */
public
static
final
String
param_merAbbr
=
"merAbbr"
;
/** 二级商户代码. */
public
static
final
String
param_subMerId
=
"subMerId"
;
/** 二级商户名称. */
public
static
final
String
param_subMerName
=
"subMerName"
;
/** 二级商户简称. */
public
static
final
String
param_subMerAbbr
=
"subMerAbbr"
;
/** Cupsecure 商户代码. */
public
static
final
String
param_csMerId
=
"csMerId"
;
/** 商户订单号. */
public
static
final
String
param_orderId
=
"orderId"
;
/** 交易时间. */
public
static
final
String
param_txnTime
=
"txnTime"
;
/** 发送时间. */
public
static
final
String
param_txnSendTime
=
"txnSendTime"
;
/** 订单超时时间间隔. */
public
static
final
String
param_orderTimeoutInterval
=
"orderTimeoutInterval"
;
/** 支付超时时间. */
public
static
final
String
param_payTimeoutTime
=
"payTimeoutTime"
;
/** 默认支付方式. */
public
static
final
String
param_defaultPayType
=
"defaultPayType"
;
/** 支持支付方式. */
public
static
final
String
param_supPayType
=
"supPayType"
;
/** 支付方式. */
public
static
final
String
param_payType
=
"payType"
;
/** 自定义支付方式. */
public
static
final
String
param_customPayType
=
"customPayType"
;
/** 物流标识. */
public
static
final
String
param_shippingFlag
=
"shippingFlag"
;
/** 收货地址-国家. */
public
static
final
String
param_shippingCountryCode
=
"shippingCountryCode"
;
/** 收货地址-省. */
public
static
final
String
param_shippingProvinceCode
=
"shippingProvinceCode"
;
/** 收货地址-市. */
public
static
final
String
param_shippingCityCode
=
"shippingCityCode"
;
/** 收货地址-地区. */
public
static
final
String
param_shippingDistrictCode
=
"shippingDistrictCode"
;
/** 收货地址-详细. */
public
static
final
String
param_shippingStreet
=
"shippingStreet"
;
/** 商品总类. */
public
static
final
String
param_commodityCategory
=
"commodityCategory"
;
/** 商品名称. */
public
static
final
String
param_commodityName
=
"commodityName"
;
/** 商品URL. */
public
static
final
String
param_commodityUrl
=
"commodityUrl"
;
/** 商品单价. */
public
static
final
String
param_commodityUnitPrice
=
"commodityUnitPrice"
;
/** 商品数量. */
public
static
final
String
param_commodityQty
=
"commodityQty"
;
/** 是否预授权. */
public
static
final
String
param_isPreAuth
=
"isPreAuth"
;
/** 币种. */
public
static
final
String
param_currencyCode
=
"currencyCode"
;
/** 账户类型. */
public
static
final
String
param_accType
=
"accType"
;
/** 账号. */
public
static
final
String
param_accNo
=
"accNo"
;
/** 支付卡类型. */
public
static
final
String
param_payCardType
=
"payCardType"
;
/** 发卡机构代码. */
public
static
final
String
param_issInsCode
=
"issInsCode"
;
/** 持卡人信息. */
public
static
final
String
param_customerInfo
=
"customerInfo"
;
/** 交易金额. */
public
static
final
String
param_txnAmt
=
"txnAmt"
;
/** 余额. */
public
static
final
String
param_balance
=
"balance"
;
/** 地区代码. */
public
static
final
String
param_districtCode
=
"districtCode"
;
/** 附加地区代码. */
public
static
final
String
param_additionalDistrictCode
=
"additionalDistrictCode"
;
/** 账单类型. */
public
static
final
String
param_billType
=
"billType"
;
/** 账单号码. */
public
static
final
String
param_billNo
=
"billNo"
;
/** 账单月份. */
public
static
final
String
param_billMonth
=
"billMonth"
;
/** 账单查询要素. */
public
static
final
String
param_billQueryInfo
=
"billQueryInfo"
;
/** 账单详情. */
public
static
final
String
param_billDetailInfo
=
"billDetailInfo"
;
/** 账单金额. */
public
static
final
String
param_billAmt
=
"billAmt"
;
/** 账单金额符号. */
public
static
final
String
param_billAmtSign
=
"billAmtSign"
;
/** 绑定标识号. */
public
static
final
String
param_bindId
=
"bindId"
;
/** 风险级别. */
public
static
final
String
param_riskLevel
=
"riskLevel"
;
/** 绑定信息条数. */
public
static
final
String
param_bindInfoQty
=
"bindInfoQty"
;
/** 绑定信息集. */
public
static
final
String
param_bindInfoList
=
"bindInfoList"
;
/** 批次号. */
public
static
final
String
param_batchNo
=
"batchNo"
;
/** 总笔数. */
public
static
final
String
param_totalQty
=
"totalQty"
;
/** 总金额. */
public
static
final
String
param_totalAmt
=
"totalAmt"
;
/** 文件类型. */
public
static
final
String
param_fileType
=
"fileType"
;
/** 文件名称. */
public
static
final
String
param_fileName
=
"fileName"
;
/** 批量文件内容. */
public
static
final
String
param_fileContent
=
"fileContent"
;
/** 商户摘要. */
public
static
final
String
param_merNote
=
"merNote"
;
/** 商户自定义域. */
// public static final String param_merReserved = "merReserved";//接口变更删除
/** 请求方保留域. */
public
static
final
String
param_reqReserved
=
"reqReserved"
;
// 新增接口
/** 保留域. */
public
static
final
String
param_reserved
=
"reserved"
;
/** 终端号. */
public
static
final
String
param_termId
=
"termId"
;
/** 终端类型. */
public
static
final
String
param_termType
=
"termType"
;
/** 交互模式. */
public
static
final
String
param_interactMode
=
"interactMode"
;
/** 发卡机构识别模式. */
// public static final String param_recognitionMode = "recognitionMode";
public
static
final
String
param_issuerIdentifyMode
=
"issuerIdentifyMode"
;
// 接口名称变更
/** 商户端用户号. */
public
static
final
String
param_merUserId
=
"merUserId"
;
/** 持卡人IP. */
public
static
final
String
param_customerIp
=
"customerIp"
;
/** 查询流水号. */
public
static
final
String
param_queryId
=
"queryId"
;
/** 原交易查询流水号. */
public
static
final
String
param_origQryId
=
"origQryId"
;
/** 系统跟踪号. */
public
static
final
String
param_traceNo
=
"traceNo"
;
/** 交易传输时间. */
public
static
final
String
param_traceTime
=
"traceTime"
;
/** 清算日期. */
public
static
final
String
param_settleDate
=
"settleDate"
;
/** 清算币种. */
public
static
final
String
param_settleCurrencyCode
=
"settleCurrencyCode"
;
/** 清算金额. */
public
static
final
String
param_settleAmt
=
"settleAmt"
;
/** 清算汇率. */
public
static
final
String
param_exchangeRate
=
"exchangeRate"
;
/** 兑换日期. */
public
static
final
String
param_exchangeDate
=
"exchangeDate"
;
/** 响应时间. */
public
static
final
String
param_respTime
=
"respTime"
;
/** 原交易应答码. */
public
static
final
String
param_origRespCode
=
"origRespCode"
;
/** 原交易应答信息. */
public
static
final
String
param_origRespMsg
=
"origRespMsg"
;
/** 应答码. */
public
static
final
String
param_respCode
=
"respCode"
;
/** 应答码信息. */
public
static
final
String
param_respMsg
=
"respMsg"
;
// 新增四个报文字段merUserRegDt merUserEmail checkFlag activateStatus
/** 商户端用户注册时间. */
public
static
final
String
param_merUserRegDt
=
"merUserRegDt"
;
/** 商户端用户注册邮箱. */
public
static
final
String
param_merUserEmail
=
"merUserEmail"
;
/** 验证标识. */
public
static
final
String
param_checkFlag
=
"checkFlag"
;
/** 开通状态. */
public
static
final
String
param_activateStatus
=
"activateStatus"
;
/** 加密证书ID. */
public
static
final
String
param_encryptCertId
=
"encryptCertId"
;
/** 用户MAC、IMEI串号、SSID. */
public
static
final
String
param_userMac
=
"userMac"
;
/** 关联交易. */
// public static final String param_relationTxnType = "relationTxnType";
/** 短信类型 */
public
static
final
String
param_smsType
=
"smsType"
;
/** 风控信息域 */
public
static
final
String
param_riskCtrlInfo
=
"riskCtrlInfo"
;
/** IC卡交易信息域 */
public
static
final
String
param_ICTransData
=
"ICTransData"
;
/** VPC交易信息域 */
public
static
final
String
param_VPCTransData
=
"VPCTransData"
;
/** 安全类型 */
public
static
final
String
param_securityType
=
"securityType"
;
/** 银联订单号 */
public
static
final
String
param_tn
=
"tn"
;
/** 分期付款手续费率 */
public
static
final
String
param_instalRate
=
"instalRate"
;
/** 分期付款手续费率 */
public
static
final
String
param_mchntFeeSubsidy
=
"mchntFeeSubsidy"
;
/** 签名公钥证书 */
public
static
final
String
param_signPubKeyCert
=
"signPubKeyCert"
;
/** 加密公钥证书 */
public
static
final
String
param_encryptPubKeyCert
=
"encryptPubKeyCert"
;
/** 证书类型 */
public
static
final
String
param_certType
=
"certType"
;
/** 二维码接口签名方法. */
public
static
final
String
param_signType
=
"signType"
;
/** 二维码接口交易类型. */
public
static
final
String
param_reqType
=
"reqType"
;
}
liquidnet-bus-service/liquidnet-service-dragon/liquidnet-service-dragon-impl/src/main/java/com/liquidnet/service/dragon/channel/unionpay/sdk/SDKUtil.java
0 → 100644
View file @
70db7894
/**
*
* Licensed Property to China UnionPay Co., Ltd.
*
* (C) Copyright of China UnionPay Co., Ltd. 2010
* All Rights Reserved.
*
*
* Modification History:
* =============================================================================
* Author Date Description
* ------------ ---------- ---------------------------------------------------
* xshu 2014-05-28 MPI工具类
* =============================================================================
*/
package
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.codec.DecoderException
;
import
org.apache.commons.codec.binary.Base64
;
import
org.apache.commons.codec.binary.Hex
;
import
java.io.ByteArrayOutputStream
;
import
java.io.IOException
;
import
java.io.UnsupportedEncodingException
;
import
java.net.URLDecoder
;
import
java.net.URLEncoder
;
import
java.security.PublicKey
;
import
java.util.*
;
import
java.util.zip.Deflater
;
import
java.util.zip.Inflater
;
import
static
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
.
SDKConstants
.*;
/**
*
* @ClassName SDKUtil
* @Description acpsdk工具类
* @date 2016-7-22 下午4:06:18
*/
@Slf4j
public
class
SDKUtil
{
/**
* 全渠道5.0、二维码signType=01用。
* 1. 按ascii排序。【注意不是字母顺序】
* 2. 对1的结果sha1得到byte数组。
* 3. 对2的结果用16进制小写字符串表示。【注意必须是小写】
* 4. 对3的结果取byte数组。【注意不是16进制字符串转byte数组,而是当普通字符串转】
* 5. 对4的结果用私钥算签名,算法为sha1withrsa。
* 6. 对5的结果做base64,得到一个字符串就是签名。
* @param data
* @param certPath
* @param certPwd
* @param encoding
* @return
*/
public
static
String
signRsa
(
Map
<
String
,
String
>
data
,
String
certPath
,
String
certPwd
,
String
encoding
)
{
try
{
String
stringData
=
createLinkString
(
data
,
true
,
false
,
encoding
);
log
.
info
(
"打印排序后待签名请求报文串(交易返回11验证签名失败时可以用来同正确的进行比对):["
+
stringData
+
"]"
);
byte
[]
sha1
=
SecureUtil
.
sha1
(
stringData
.
getBytes
(
encoding
));
String
sha1Hex
=
byteArrayToHexString
(
sha1
).
toLowerCase
();
log
.
info
(
"sha1结果(交易返回11验证签名失败可以用来同正确的进行比对):["
+
sha1Hex
+
"]"
);
return
Base64
.
encodeBase64String
(
SecureUtil
.
getSignature
(
CertUtil
.
getSignCertPrivateKeyByStoreMap
(
certPath
,
certPwd
),
sha1Hex
.
getBytes
()));
}
catch
(
Exception
e
)
{
log
.
error
(
"calcSignRsa Error"
,
e
);
return
null
;
}
}
/**
* 全渠道5.1signMethod=01、二维码signType=02(以及少数接口)用。
* 1. 按ascii排序。【注意不是字母顺序】
* 2. 对1的结果sha256得到byte数组。
* 3. 对2的结果用16进制小写字符串表示。【注意必须是小写】
* 4. 对3的结果取byte数组。【注意不是16进制字符串转byte数组,而是当普通字符串转】
* 5. 对4的结果用私钥算签名,算法为sha256withrsa。
* 6. 对5的结果做base64,得到一个字符串就是签名。
* @param data
* @param certPath
* @param certPwd
* @param encoding
* @return
*/
public
static
String
signRsa2
(
Map
<
String
,
String
>
data
,
String
certPath
,
String
certPwd
,
String
encoding
)
{
try
{
String
stringData
=
createLinkString
(
data
,
true
,
false
,
encoding
);
log
.
info
(
"打印排序后待签名请求报文串(交易返回11验证签名失败时可以用来同正确的进行比对):["
+
stringData
+
"]"
);
byte
[]
sha256
=
SecureUtil
.
sha256
(
stringData
.
getBytes
(
encoding
));
String
sha256Hex
=
byteArrayToHexString
(
sha256
).
toLowerCase
();
log
.
info
(
"sha256(交易返回11验证签名失败可以用来同正确的进行比对):["
+
sha256Hex
+
"]"
);
return
Base64
.
encodeBase64String
(
SecureUtil
.
getSignatureSHA256
(
CertUtil
.
getSignCertPrivateKeyByStoreMap
(
certPath
,
certPwd
),
sha256Hex
.
getBytes
()));
}
catch
(
Exception
e
)
{
log
.
error
(
"calcSignRsa2 Error"
,
e
);
return
null
;
}
}
/**
* 全渠道5.1signMethod=11用。
* @param data
* @param encoding
* @return
*/
public
static
String
signSha256
(
Map
<
String
,
String
>
data
,
String
secureKey
,
String
encoding
)
{
String
sorted
=
createLinkString
(
data
,
true
,
false
,
encoding
);
log
.
info
(
"排序串:["
+
sorted
+
"]"
);
return
SDKUtil
.
calcSignSha256
(
sorted
,
secureKey
,
encoding
);
}
/**
* 全渠道5.1signMethod=12用。
* @param data
* @param encoding
* @return
*/
public
static
String
signSm3
(
Map
<
String
,
String
>
data
,
String
secureKey
,
String
encoding
)
{
String
sorted
=
createLinkString
(
data
,
true
,
false
,
encoding
);
log
.
info
(
"排序串:["
+
sorted
+
"]"
);
return
SDKUtil
.
calcSignSm3
(
sorted
,
secureKey
,
encoding
);
}
private
static
String
calcSignSm3
(
String
sorted
,
String
secureKey
,
String
encoding
)
{
try
{
String
s
=
sorted
+
SDKConstants
.
AMPERSAND
+
byteArrayToHexString
(
SecureUtil
.
sm3
(
secureKey
.
getBytes
(
encoding
)));
return
byteArrayToHexString
(
SecureUtil
.
sm3
(
s
.
getBytes
(
encoding
)));
}
catch
(
Exception
e
)
{
log
.
error
(
"calcSignSm3 Error"
,
e
);
return
null
;
}
}
private
static
String
calcSignSha256
(
String
sorted
,
String
secureKey
,
String
encoding
)
{
try
{
String
s
=
sorted
+
SDKConstants
.
AMPERSAND
+
byteArrayToHexString
(
SecureUtil
.
sha256
(
secureKey
.
getBytes
(
encoding
)));
return
byteArrayToHexString
(
SecureUtil
.
sha256
(
s
.
getBytes
(
encoding
)));
}
catch
(
Exception
e
)
{
log
.
error
(
"calcSignSha256 Error"
,
e
);
return
null
;
}
}
/**
* 全渠道5.0接口、二维码signType=01用。
* @param resData
* @param encoding
* @return
*/
public
static
boolean
verifyRsa
(
Map
<
String
,
String
>
resData
,
PublicKey
pubKey
,
String
encoding
)
{
try
{
String
stringSign
=
resData
.
remove
(
SDKConstants
.
param_signature
);
if
(
isEmpty
(
stringSign
))
{
log
.
error
(
"signature is null. verifyRsa fail."
);
return
false
;
}
log
.
info
(
"签名原文:["
+
stringSign
+
"]"
);
String
stringData
=
createLinkString
(
resData
,
true
,
false
,
encoding
);
log
.
info
(
"待验签排序串:["
+
stringData
+
"]"
);
byte
[]
sha1
=
SecureUtil
.
sha1
(
stringData
.
getBytes
(
encoding
));
String
sha1Hex
=
byteArrayToHexString
(
sha1
).
toLowerCase
();
log
.
info
(
"sha1结果:["
+
sha1Hex
+
"]"
);
return
SecureUtil
.
verifySignature
(
pubKey
,
sha1Hex
.
getBytes
(
encoding
),
Base64
.
decodeBase64
(
stringSign
));
}
catch
(
Exception
e
)
{
log
.
error
(
"verifyRsa fail."
+
e
.
getMessage
(),
e
);
return
false
;
}
}
/**
* 全渠道5.1、二维码signType=02用。
* @param resData
* @param encoding
* @param publicKey
* @return
*/
public
static
boolean
verifyRsa2
(
Map
<
String
,
String
>
resData
,
PublicKey
publicKey
,
String
encoding
)
{
try
{
String
stringSign
=
resData
.
remove
(
SDKConstants
.
param_signature
);
if
(
isEmpty
(
stringSign
))
{
log
.
error
(
"signature is null. verifyRsa2 fail."
);
return
false
;
}
log
.
info
(
"签名原文:["
+
stringSign
+
"]"
);
String
stringData
=
createLinkString
(
resData
,
true
,
false
,
encoding
);
log
.
info
(
"待验签排序串:["
+
stringData
+
"]"
);
byte
[]
sha256
=
SecureUtil
.
sha256
(
stringData
.
getBytes
(
encoding
));
String
sha256Hex
=
byteArrayToHexString
(
sha256
).
toLowerCase
();
log
.
info
(
"sha256结果:["
+
sha256Hex
+
"]"
);
boolean
result
=
SecureUtil
.
verifySignatureSHA256
(
publicKey
,
sha256Hex
.
getBytes
(
encoding
),
Base64
.
decodeBase64
(
stringSign
));
log
.
info
(
"验证签名"
+
(
result
?
"成功"
:
"失败"
));
return
result
;
}
catch
(
Exception
e
)
{
log
.
error
(
"verifyRsa2 fail."
+
e
.
getMessage
(),
e
);
return
false
;
}
}
public
static
boolean
verifySha256
(
Map
<
String
,
String
>
resData
,
String
secureKey
,
String
encoding
){
try
{
if
(
isEmpty
(
secureKey
))
{
log
.
error
(
"secureKey is null. verifySha256 fail."
);
return
false
;
}
String
sign
=
resData
.
remove
(
SDKConstants
.
param_signature
);
if
(
isEmpty
(
sign
))
{
log
.
error
(
"signature is null. verifySha256 fail."
);
return
false
;
}
log
.
info
(
"签名原文:["
+
sign
+
"]"
);
String
sorted
=
createLinkString
(
resData
,
true
,
false
,
encoding
);
log
.
info
(
"排序串:["
+
sorted
+
"]"
);
String
expectedSign
=
calcSignSha256
(
sorted
,
secureKey
,
encoding
);
boolean
result
=
sign
.
equals
(
expectedSign
);
if
(!
result
)
log
.
error
(
"验签失败,签名预期:"
+
expectedSign
+
", 签名实际:"
+
sign
);
else
log
.
info
(
"验签成功"
);
return
result
;
}
catch
(
Exception
e
)
{
log
.
error
(
"verifySha256 fail."
+
e
.
getMessage
(),
e
);
return
false
;
}
}
public
static
boolean
verifySm3
(
Map
<
String
,
String
>
resData
,
String
secureKey
,
String
encoding
){
try
{
if
(
isEmpty
(
secureKey
))
{
log
.
error
(
"secureKey is null. verifySm3 fail."
);
return
false
;
}
String
sign
=
resData
.
remove
(
SDKConstants
.
param_signature
);
if
(
isEmpty
(
sign
))
{
log
.
error
(
"signature is null. verifySm3 fail."
);
return
false
;
}
log
.
info
(
"签名原文:["
+
sign
+
"]"
);
String
sorted
=
createLinkString
(
resData
,
true
,
false
,
encoding
);
log
.
info
(
"排序串:["
+
sorted
+
"]"
);
String
expectedSign
=
calcSignSm3
(
sorted
,
secureKey
,
encoding
);
boolean
result
=
sign
.
equals
(
expectedSign
);
if
(!
result
)
log
.
error
(
"验签失败,签名预期:"
+
expectedSign
+
", 签名实际:"
+
sign
);
else
log
.
info
(
"验签成功"
);
return
result
;
}
catch
(
Exception
e
)
{
log
.
error
(
"verifySm3 fail."
+
e
.
getMessage
(),
e
);
return
false
;
}
}
/**
* 把请求要素按照“参数=参数值”的模式用“&”字符拼接成字符串
*
* @param para
* 请求要素
* @param sort
* 是否需要根据key值作升序排列
* @param encode
* 是否需要URL编码
* @return 拼接成的字符串
*/
public
static
String
createLinkString
(
Map
<
String
,
String
>
para
,
boolean
sort
,
boolean
encode
,
String
charset
)
{
List
<
String
>
keys
=
new
ArrayList
<
String
>(
para
.
keySet
());
if
(
sort
)
Collections
.
sort
(
keys
);
StringBuilder
sb
=
new
StringBuilder
();
for
(
int
i
=
0
;
i
<
keys
.
size
();
i
++)
{
String
key
=
keys
.
get
(
i
);
String
value
=
para
.
get
(
key
);
if
(
encode
&&
value
!=
null
)
{
try
{
value
=
URLEncoder
.
encode
(
value
,
charset
);
}
catch
(
UnsupportedEncodingException
e
)
{
throw
new
RuntimeException
(
charset
+
"送错了."
);
}
}
if
(
i
==
keys
.
size
()
-
1
)
{
// 拼接时,不包括最后一个&字符
sb
.
append
(
key
).
append
(
"="
).
append
(
value
);
}
else
{
sb
.
append
(
key
).
append
(
"="
).
append
(
value
).
append
(
"&"
);
}
}
return
sb
.
toString
();
}
/**
* 解析应答字符串,生成应答要素。
* 解析全渠道5.0、5.1,二维码的应答报文时不要用这个方法哦。
* @param str 需要解析的字符串
* @param charset
* @return 解析的结果map
* @throws UnsupportedEncodingException
*/
public
static
Map
<
String
,
String
>
parseQString
(
String
str
,
String
charset
)
{
if
(
str
==
null
||
str
.
length
()
==
0
)
return
new
HashMap
<
String
,
String
>();
Map
<
String
,
String
>
map
=
new
HashMap
<
String
,
String
>();
int
len
=
str
.
length
();
StringBuilder
temp
=
new
StringBuilder
();
char
curChar
;
String
key
=
null
;
boolean
isKey
=
true
;
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
// 遍历整个带解析的字符串
curChar
=
str
.
charAt
(
i
);
// 取当前字符
if
(
curChar
==
'&'
)
{
// 如果读取到&分割符
putKeyValueToMap
(
temp
,
isKey
,
key
,
map
,
true
,
charset
);
temp
.
setLength
(
0
);
isKey
=
true
;
}
else
{
if
(
isKey
)
{
// 如果当前生成的是key
if
(
curChar
==
'='
)
{
// 如果读取到=分隔符
key
=
temp
.
toString
();
temp
.
setLength
(
0
);
isKey
=
false
;
}
else
{
temp
.
append
(
curChar
);
}
}
else
{
// 如果当前生成的是value
temp
.
append
(
curChar
);
}
}
}
putKeyValueToMap
(
temp
,
isKey
,
key
,
map
,
true
,
charset
);
return
map
;
}
/**
* 解析应答字符串,生成应答要素。
* 处理全渠道应答报文那种不带url编码又可能在value里成对出现括号且括号里带&和=的情况。
* 报文解析工具本身用不到,给验签的小工具用。
*
* @param str 需要解析的字符串
* @return 解析的结果map
* @throws UnsupportedEncodingException
*/
public
static
Map
<
String
,
String
>
parseRespString
(
String
str
)
{
if
(
str
==
null
||
str
.
length
()
==
0
)
return
new
HashMap
<
String
,
String
>();
Map
<
String
,
String
>
map
=
new
HashMap
<
String
,
String
>();
int
len
=
str
.
length
();
StringBuilder
temp
=
new
StringBuilder
();
char
curChar
;
String
key
=
null
;
boolean
isKey
=
true
;
boolean
isOpen
=
false
;
//值里有嵌套
char
openName
=
0
;
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
// 遍历整个带解析的字符串
curChar
=
str
.
charAt
(
i
);
// 取当前字符
if
(
isKey
)
{
// 如果当前生成的是key
if
(
curChar
==
'='
)
{
// 如果读取到=分隔符
key
=
temp
.
toString
();
temp
.
setLength
(
0
);
isKey
=
false
;
}
else
{
temp
.
append
(
curChar
);
}
}
else
{
// 如果当前生成的是value
if
(
isOpen
){
if
(
curChar
==
openName
){
isOpen
=
false
;
}
}
else
{
//如果没开启嵌套
if
(
curChar
==
'{'
){
//如果碰到,就开启嵌套
isOpen
=
true
;
openName
=
'}'
;
}
if
(
curChar
==
'['
){
isOpen
=
true
;
openName
=
']'
;
}
}
if
(
curChar
==
'&'
&&
!
isOpen
)
{
// 如果读取到&分割符,同时这个分割符不是值域,这时将map里添加
putKeyValueToMap
(
temp
,
isKey
,
key
,
map
,
false
,
null
);
temp
.
setLength
(
0
);
isKey
=
true
;
}
else
{
temp
.
append
(
curChar
);
}
}
}
putKeyValueToMap
(
temp
,
isKey
,
key
,
map
,
false
,
null
);
return
map
;
}
private
static
void
putKeyValueToMap
(
StringBuilder
temp
,
boolean
isKey
,
String
key
,
Map
<
String
,
String
>
map
,
boolean
decode
,
String
charset
)
{
try
{
if
(
decode
)
{
key
=
URLDecoder
.
decode
(
key
,
charset
);
}
if
(
isKey
)
{
key
=
temp
.
toString
();
map
.
put
(
key
,
""
);
}
else
{
if
(
decode
)
{
String
value
=
URLDecoder
.
decode
(
temp
.
toString
(),
charset
);
map
.
put
(
key
,
value
);
}
else
{
map
.
put
(
key
,
temp
.
toString
());
}
}
}
catch
(
UnsupportedEncodingException
e
)
{
throw
new
RuntimeException
(
"编码有问题: "
+
charset
);
}
}
/**
*
* 获取应答报文中的加密公钥证书,并存储到本地,并备份原始证书<br>
* 更新成功则返回1,无更新返回0,失败异常返回-1。
*
* @param strCert
* @param certType
* @return
*/
public
static
int
updateEncryptCert
(
String
strCert
,
String
certType
)
{
if
(
isEmpty
(
strCert
)
||
isEmpty
(
certType
))
return
-
1
;
if
(
CERTTYPE_01
.
equals
(
certType
))
{
// 更新敏感信息加密公钥
return
CertUtil
.
resetEncryptCertPublicKey
(
strCert
);
}
else
if
(
CERTTYPE_02
.
equals
(
certType
))
{
// 更新pin敏感信息加密公钥
return
CertUtil
.
resetPinEncryptCertPublicKey
(
strCert
);
}
else
{
log
.
info
(
"unknown cerType:"
+
certType
);
return
-
1
;
}
}
/**
* 过滤请求报文中的空字符串或者空字符串
* @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
(!
isEmpty
(
value
))
{
submitFromData
.
put
(
key
,
value
.
trim
());
//不知道为啥一直有个trim,如果值里自带空格岂不是要出bug……但一直就这样,先 不管它吧。
}
}
return
submitFromData
;
}
/**
* 解压缩.
*
* @param inputByte
* byte[]数组类型的数据
* @return 解压缩后的数据
* @throws IOException
*/
public
static
byte
[]
inflater
(
final
byte
[]
inputByte
)
throws
IOException
{
int
compressedDataLength
=
0
;
Inflater
compresser
=
new
Inflater
(
false
);
compresser
.
setInput
(
inputByte
,
0
,
inputByte
.
length
);
ByteArrayOutputStream
o
=
new
ByteArrayOutputStream
(
inputByte
.
length
);
byte
[]
result
=
new
byte
[
1024
];
try
{
while
(!
compresser
.
finished
())
{
compressedDataLength
=
compresser
.
inflate
(
result
);
if
(
compressedDataLength
==
0
)
{
break
;
}
o
.
write
(
result
,
0
,
compressedDataLength
);
}
}
catch
(
Exception
ex
)
{
log
.
error
(
"Data format error!"
,
ex
);
}
finally
{
o
.
close
();
}
compresser
.
end
();
return
o
.
toByteArray
();
}
/**
* 压缩.
*
* @param inputByte
* 需要解压缩的byte[]数组
* @return 压缩后的数据
* @throws IOException
*/
public
static
byte
[]
deflater
(
final
byte
[]
inputByte
)
throws
IOException
{
int
compressedDataLength
=
0
;
Deflater
compresser
=
new
Deflater
();
compresser
.
setInput
(
inputByte
);
compresser
.
finish
();
ByteArrayOutputStream
o
=
new
ByteArrayOutputStream
(
inputByte
.
length
);
byte
[]
result
=
new
byte
[
1024
];
try
{
while
(!
compresser
.
finished
())
{
compressedDataLength
=
compresser
.
deflate
(
result
);
o
.
write
(
result
,
0
,
compressedDataLength
);
}
}
finally
{
o
.
close
();
}
compresser
.
end
();
return
o
.
toByteArray
();
}
/**
* 判断字符串是否为NULL或空
*
* @param s
* 待判断的字符串数据
* @return 判断结果 true-是 false-否
*/
public
static
boolean
isEmpty
(
String
s
)
{
return
null
==
s
||
""
.
equals
(
s
.
trim
());
}
/**
*
* @param hexString
* @return
*/
public
static
byte
[]
hexStringToByteArray
(
String
hexString
){
try
{
return
Hex
.
decodeHex
(
hexString
.
toCharArray
());
}
catch
(
DecoderException
e
)
{
log
.
error
(
"非正常16进制字符串"
+
hexString
,
e
);
return
null
;
}
}
/**
*
* @param bytes
* @return 16进制字符串,小写
*/
public
static
String
byteArrayToHexString
(
byte
[]
bytes
){
return
new
String
(
Hex
.
encodeHex
(
bytes
,
true
));
}
}
liquidnet-bus-service/liquidnet-service-dragon/liquidnet-service-dragon-impl/src/main/java/com/liquidnet/service/dragon/channel/unionpay/sdk/SecureUtil.java
0 → 100644
View file @
70db7894
/**
*
* Licensed Property to China UnionPay Co., Ltd.
*
* (C) Copyright of China UnionPay Co., Ltd. 2010
* All Rights Reserved.
*
*
* Modification History:
* =============================================================================
* Author Date Description
* ------------ ---------- ---------------------------------------------------
* xshu 2014-05-28 报文加密解密等操作的工具类
* =============================================================================
*/
package
com
.
liquidnet
.
service
.
dragon
.
channel
.
unionpay
.
sdk
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.codec.binary.Hex
;
import
org.bouncycastle.crypto.digests.SM3Digest
;
import
javax.crypto.Cipher
;
import
javax.crypto.SecretKey
;
import
javax.crypto.SecretKeyFactory
;
import
javax.crypto.spec.DESedeKeySpec
;
import
java.security.*
;
import
java.util.Arrays
;
/**
*
* @ClassName SecureUtil
* @Description acpsdk安全算法工具类
* @date 2016-7-22 下午4:08:32
*/
@Slf4j
public
class
SecureUtil
{
/**
* @param bytes
* @return
*/
public
static
byte
[]
sha1
(
byte
[]
bytes
)
{
try
{
MessageDigest
messageDigest
=
MessageDigest
.
getInstance
(
"SHA-1"
);
messageDigest
.
update
(
bytes
);
return
messageDigest
.
digest
();
}
catch
(
NoSuchAlgorithmException
e
)
{
log
.
error
(
"SHA1计算失败"
,
e
);
return
null
;
}
}
/**
* @param bytes
* @return
*/
public
static
byte
[]
sha256
(
byte
[]
bytes
)
{
try
{
MessageDigest
messageDigest
=
MessageDigest
.
getInstance
(
"SHA-256"
);
messageDigest
.
update
(
bytes
);
return
messageDigest
.
digest
();
}
catch
(
Exception
e
)
{
log
.
error
(
"SHA256计算失败"
,
e
);
return
null
;
}
}
/**
* @param bytes
* @return
*/
public
static
byte
[]
sm3
(
byte
[]
bytes
)
{
SM3Digest
sm3
=
new
SM3Digest
();
sm3
.
update
(
bytes
,
0
,
bytes
.
length
);
byte
[]
result
=
new
byte
[
sm3
.
getDigestSize
()];
sm3
.
doFinal
(
result
,
0
);
return
result
;
}
public
static
byte
[]
getSignature
(
PrivateKey
priKey
,
byte
[]
digest
)
{
byte
[]
mesDigest
;
Signature
sig
;
try
{
sig
=
Signature
.
getInstance
(
"SHA1withRSA"
);
sig
.
initSign
(
priKey
);
sig
.
update
(
digest
);
mesDigest
=
sig
.
sign
();
return
mesDigest
;
}
catch
(
Exception
e
)
{
log
.
error
(
"签名计算失败"
,
e
);
return
null
;
}
}
public
static
byte
[]
getSignatureSHA256
(
PrivateKey
priKey
,
byte
[]
digest
)
{
byte
[]
mesDigest
;
Signature
sig
;
try
{
sig
=
Signature
.
getInstance
(
"SHA256withRSA"
);
sig
.
initSign
(
priKey
);
sig
.
update
(
digest
);
mesDigest
=
sig
.
sign
();
return
mesDigest
;
}
catch
(
Exception
e
)
{
log
.
error
(
"签名计算失败"
,
e
);
return
null
;
}
}
public
static
boolean
verifySignature
(
PublicKey
pubKey
,
byte
[]
digest
,
byte
[]
signature
)
{
try
{
Signature
sig
=
Signature
.
getInstance
(
"SHA1withRSA"
);
sig
.
initVerify
(
pubKey
);
sig
.
update
(
digest
);
boolean
ok
=
sig
.
verify
(
signature
);
return
ok
;
}
catch
(
Exception
e
)
{
log
.
error
(
"验签异常"
,
e
);
return
false
;
}
}
public
static
boolean
verifySignatureSHA256
(
PublicKey
pubKey
,
byte
[]
digest
,
byte
[]
signature
)
{
if
(
pubKey
==
null
||
digest
==
null
||
signature
==
null
)
{
if
(
pubKey
==
null
){
log
.
error
(
"验签时pubKey传入了空值,验签失败"
);
}
else
if
(
digest
==
null
){
log
.
error
(
"验签时digest传入了空值,验签失败"
);
}
else
if
(
signature
==
null
){
log
.
error
(
"验签时signature传入了空值,验签失败"
);
}
else
{
log
.
error
(
"验签时传入了空值,验签失败"
);
}
return
false
;
}
try
{
Signature
sig
=
Signature
.
getInstance
(
"SHA256withRSA"
);
sig
.
initVerify
(
pubKey
);
sig
.
update
(
digest
);
boolean
ok
=
sig
.
verify
(
signature
);
return
ok
;
}
catch
(
Exception
e
)
{
log
.
error
(
"验签异常"
,
e
);
return
false
;
}
}
public
static
byte
[]
encrypt
(
Key
key
,
byte
[]
data
)
{
try
{
Cipher
cipher
=
Cipher
.
getInstance
(
"RSA/ECB/PKCS1Padding"
);
cipher
.
init
(
Cipher
.
ENCRYPT_MODE
,
key
);
return
cipher
.
doFinal
(
data
);
}
catch
(
Exception
e
)
{
log
.
error
(
"加密失败"
,
e
);
return
null
;
}
}
public
static
byte
[]
decrypt
(
Key
Key
,
byte
[]
data
)
{
try
{
Cipher
cipher
=
Cipher
.
getInstance
(
"RSA/ECB/PKCS1Padding"
);
cipher
.
init
(
Cipher
.
DECRYPT_MODE
,
Key
);
return
cipher
.
doFinal
(
data
);
}
catch
(
Exception
e
)
{
log
.
error
(
"解密失败"
,
e
);
return
null
;
}
}
/**
* ANSIX9.8格式(带主账号信息)pinblock
* @param pan 卡号
* @param pin
* @return
*/
public
static
byte
[]
pinblock
(
String
pan
,
String
pin
){
if
(
SDKUtil
.
isEmpty
(
pan
)
||
SDKUtil
.
isEmpty
(
pin
)){
log
.
error
(
"卡号或pin为空,无法算pinblock。"
);
return
null
;
}
pan
=
pan
.
trim
();
pin
=
pin
.
trim
();
if
(!
pan
.
matches
(
"^[0-9]{13,19}$"
))
{
log
.
error
(
"卡号格式不对,无法算pinblock。"
);
return
null
;
}
if
(!
pin
.
matches
(
"^[0-9]{4,6}$"
))
{
log
.
error
(
"pin格式不对,无法算pinblock。"
);
return
null
;
}
pan
=
(
"0000"
)
+
pan
.
substring
(
pan
.
length
()
-
13
,
pan
.
length
()
-
1
);
int
blockLen
=
8
;
try
{
pin
=
"0"
+
pin
.
length
()
+
pin
;
byte
[]
pinbyte
=
Arrays
.
copyOf
(
Hex
.
decodeHex
(
pin
.
toCharArray
()),
blockLen
);
Arrays
.
fill
(
pinbyte
,
pin
.
length
()/
2
,
blockLen
,
(
byte
)
0xff
);
byte
[]
panbyte
=
Hex
.
decodeHex
(
pan
.
toCharArray
());
byte
[]
tempPin
=
new
byte
[
blockLen
];
for
(
int
i
=
0
;
i
<
blockLen
;
i
++)
{
tempPin
[
i
]
=
(
byte
)
(
pinbyte
[
i
]
^
panbyte
[
i
]);
}
return
tempPin
;
}
catch
(
Exception
e
){
log
.
error
(
"pinblock计算异常啦……"
,
e
);
return
null
;
}
}
// /**
// * ANSI X9.8格式(不带主账号信息)pinblock
// * @param pin
// * @return
// */
// public static byte[] pinblock(String pin){
//
// if(SDKUtil.isEmpty(pin)){
// log.error("卡号或pin为空,无法算pinblock。");
// return null;
// }
// pin = pin.trim();
// if (!pin.matches("^[0-9]{4,6}$")) {
// log.error("pin格式不对,无法算pinblock。");
// return null;
// }
// int blockLen = 8;
// try {
// pin = "0" + pin.length() + pin;
// byte[] pinbyte = Arrays.copyOf(Hex.decodeHex(pin.toCharArray()), blockLen);
// Arrays.fill(pinbyte, pin.length()/2, blockLen, (byte)0xff);
// return pinbyte;
// } catch (Exception e){
// log.error("pinblock计算异常啦……", e);
// return null;
// }
// }
public
static
byte
[]
tripleDesEncryptECBPKCS5Padding
(
byte
[]
key
,
byte
[]
data
)
{
try
{
if
(
data
==
null
||
data
.
length
%
8
!=
0
)
throw
new
IllegalArgumentException
(
"data is null or error data length."
);
SecretKey
sk
=
getTripleDesKey
(
key
);
Cipher
cipher
=
Cipher
.
getInstance
(
"DESede/ECB/PKCS5Padding"
);
cipher
.
init
(
Cipher
.
ENCRYPT_MODE
,
sk
);
return
cipher
.
doFinal
(
data
);
}
catch
(
Exception
e
)
{
log
.
error
(
"加密失败"
,
e
);
return
null
;
}
}
/**
* 后补0到位数为unitLength的整数倍
* @param value
* @return
*/
public
static
byte
[]
rightPadZero
(
byte
[]
value
,
final
int
unitLength
){
if
(
value
.
length
%
unitLength
==
0
)
return
value
;
int
len
=
(
value
.
length
/
unitLength
+
1
)
*
unitLength
;
return
Arrays
.
copyOf
(
value
,
len
);
}
/**
* 通过byte数组得到SecretKey类型的密钥
* @param key
* @return
* @throws IllegalArgumentException
*/
private
static
SecretKey
getTripleDesKey
(
byte
[]
key
)
{
if
(
key
==
null
||
!(
key
.
length
==
8
||
key
.
length
==
16
||
key
.
length
==
24
))
throw
new
IllegalArgumentException
(
"key is null or error key length."
);
byte
[]
specKey
=
new
byte
[
24
];
try
{
switch
(
key
.
length
)
{
case
16
:
System
.
arraycopy
(
key
,
0
,
specKey
,
0
,
16
);
System
.
arraycopy
(
key
,
0
,
specKey
,
16
,
8
);
break
;
case
8
:
System
.
arraycopy
(
key
,
0
,
specKey
,
0
,
8
);
System
.
arraycopy
(
key
,
0
,
specKey
,
8
,
8
);
System
.
arraycopy
(
key
,
0
,
specKey
,
16
,
8
);
break
;
case
24
:
System
.
arraycopy
(
key
,
0
,
specKey
,
0
,
24
);
break
;
default
:
throw
new
IllegalArgumentException
(
"error key length."
);
}
DESedeKeySpec
ks
=
new
DESedeKeySpec
(
specKey
);
SecretKey
sk
=
SecretKeyFactory
.
getInstance
(
"DESede"
)
.
generateSecret
(
ks
);
return
sk
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
throw
new
SecurityException
(
"exception in 3des-ecb encryption"
,
e
);
}
}
}
liquidnet-bus-service/liquidnet-service-dragon/liquidnet-service-dragon-impl/src/main/java/com/liquidnet/service/dragon/channel/unionpay/sdk/readme_and_history
0 → 100644
View file @
70db7894
【哪个sdk新就用哪个哦】【不完全向下兼容注意】
2020/9/29:
增加应答只需要关心200的post。
2020/6/23:
规范大改了,请参考最新规范进行修改。
1. 应答新增returnMsg,调整了应答码和交易状态相关字段。具体的值见规范。
目前使用的:
1)returnCode:代表此次交易请求的业务结果,查询交易表示查询操作的业务结果,具体交易结果,以交易应答码、交易状态码为准。
2)respCode:交易结果应答码。
3)xxxStatus:各类交易的状态
① transferStatus-转账状态,仅转账交易出现
② billStatus-账单状态,仅缴费交易用
③ entryStatus-入账状态,入账状态查询用
④ transStatus-消费/预授权交易的状态,仅消费和预授权查询和通知用
已删除的:resultCode、transCode、transMsg。
2. 应答新增merTransIndex,查询接口会原样应答,但目前并没有往发卡或者二维码的付款方送,大概没别的作用。
3. 应答新增preAuthId,没什么用,如果需要收单手工帮你处理预授权进行撤销或完成时可用提供他们,可方便他们处理。卡号+商户号+preAuthId在预授权超时或结束(完成或撤销)前是唯一的。
4. 新增respCode、transStatus取值TRANS_PRE_AUTH_COMPLETED,表示已被预授权完成。
5. 查询应答新增transStatus字段表示被查询的原交易的状态。
6. respCode和respMsg下沉到bizContent中.
7. traceNo和traceTime替换成清算主键settleKey,settleKey在收单和发卡的清算文件内是唯一的,可用于和收单对账,以及找银联和发卡查交易。
8. merCertId、cupCertId改为certId。
9. accessId:填写商户号。
10. accessType填写0。
11. 订单号、交易时间、商户代码从公共参数下沉到bizContent中。
12. 增加入账状态状态查询接口。
13. 转账交易termId从必填M改成可选O。
14. 两方转账也返回transferStatus。
2020/4/29:
6.0接口地址修正最终版,注意获取地址方式改getTransUrl,配置文件增加acpsdk.transUrl=https://gateway.test.95516.com/api/trans.do。
2020/4/4:
不完全向下兼容,注意对应修改,修改后的样例可参考assets/sdk测试类.
修改后:
全渠道5.0、5.1用AcpService。
全渠道6.0用Acp6Service。
二维码用QrcService。。
LogUtil删除,请改成直接调log4j或slf4j打印。
原二维码DemoBase中:
DemoBase.getAddnCond->QrcService.getKVBase64Field
DemoBase.formInfoBase64->QrcService.getKVBase64Field
DemoBase.getPayeeInfo->QrcService.getKVBase64Field
DemoBase.getPayeeInfoWithEncrpyt->QrcService.getKVEncBase64Field
DemoBase.getPayerInfo->QrcService.getKVBase64Field
DemoBase.getPayerInfoWithEncrpyt->QrcService.getKVEncBase64Field
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment