mirror of
https://gitee.com/egzosn/pay-java-parent.git
synced 2026-05-19 07:31:36 +08:00
银联基础完成
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
package com.egzosn.pay.common.api;
|
||||
|
||||
import com.egzosn.pay.common.bean.MsgType;
|
||||
import com.egzosn.pay.common.bean.result.PayException;
|
||||
import com.egzosn.pay.common.exception.PayErrorException;
|
||||
import com.egzosn.pay.common.util.sign.CertDescriptor;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
@@ -15,11 +18,19 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
*/
|
||||
public abstract class BasePayConfigStorage implements PayConfigStorage{
|
||||
|
||||
/**
|
||||
* 证书管理器
|
||||
*/
|
||||
private volatile CertDescriptor certDescriptor;
|
||||
|
||||
/**
|
||||
* 应用私钥,rsa_private pkcs8格式 生成签名时使用
|
||||
*/
|
||||
private volatile String keyPrivate;
|
||||
/**
|
||||
* 应用私钥,rsa_private pkcs8格式 生成签名时使用
|
||||
*/
|
||||
private volatile String keyPrivateCertPwd;
|
||||
/**
|
||||
* 支付平台公钥(签名校验使用)
|
||||
*/
|
||||
@@ -70,6 +81,21 @@ public abstract class BasePayConfigStorage implements PayConfigStorage{
|
||||
*/
|
||||
private boolean isTest = false;
|
||||
|
||||
/**
|
||||
* 是否为证书签名
|
||||
*/
|
||||
private boolean isCertSign = false;
|
||||
|
||||
|
||||
public CertDescriptor getCertDescriptor() {
|
||||
if (!isCertSign){
|
||||
throw new PayErrorException(new PayException("certDescriptor fail", "isCertSign is false"));
|
||||
}
|
||||
if(null == certDescriptor){
|
||||
certDescriptor = new CertDescriptor();
|
||||
}
|
||||
return certDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKeyPrivate() {
|
||||
@@ -80,6 +106,14 @@ public abstract class BasePayConfigStorage implements PayConfigStorage{
|
||||
this.keyPrivate = keyPrivate;
|
||||
}
|
||||
|
||||
public String getKeyPrivateCertPwd() {
|
||||
return keyPrivateCertPwd;
|
||||
}
|
||||
|
||||
public void setKeyPrivateCertPwd(String keyPrivateCertPwd) {
|
||||
this.keyPrivateCertPwd = keyPrivateCertPwd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKeyPublic() {
|
||||
return keyPublic;
|
||||
@@ -207,4 +241,15 @@ public abstract class BasePayConfigStorage implements PayConfigStorage{
|
||||
public void setTest(boolean test) {
|
||||
isTest = test;
|
||||
}
|
||||
|
||||
public boolean isCertSign() {
|
||||
return isCertSign;
|
||||
}
|
||||
|
||||
public void setCertSign(boolean certSign) {
|
||||
isCertSign = certSign;
|
||||
if (certSign){
|
||||
certDescriptor = new CertDescriptor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.egzosn.pay.common.api;
|
||||
|
||||
import com.egzosn.pay.common.bean.MsgType;
|
||||
import com.egzosn.pay.common.util.sign.CertDescriptor;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
@@ -14,6 +15,17 @@ import java.util.concurrent.locks.Lock;
|
||||
*/
|
||||
public interface PayConfigStorage {
|
||||
|
||||
/**
|
||||
* 获取证书解释器
|
||||
* @return 证书解释器
|
||||
*/
|
||||
CertDescriptor getCertDescriptor();
|
||||
|
||||
/**
|
||||
* 获取私钥证书密码
|
||||
* @return 私钥证书密码
|
||||
*/
|
||||
String getKeyPrivateCertPwd();
|
||||
/**
|
||||
* 应用id
|
||||
* @return 应用id
|
||||
|
||||
@@ -0,0 +1,315 @@
|
||||
/**
|
||||
*
|
||||
* 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.egzosn.pay.common.util.sign;
|
||||
|
||||
import com.egzosn.pay.common.util.str.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import java.io.*;
|
||||
import java.math.BigInteger;
|
||||
import java.security.*;
|
||||
import java.security.cert.*;
|
||||
import java.security.spec.RSAPublicKeySpec;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* @ClassName: CertDescriptor
|
||||
* @Description: acpsdk证书工具类,主要用于对证书的加载和使用
|
||||
* @date 2016-7-22 下午2:46:20
|
||||
* 声明:以下代码只是为了方便接入方测试而提供的样例代码,商户可以根据自己需要,按照技术文档编写。该代码仅供参考,不提供编码,性能,规范性等方面的保障
|
||||
*/
|
||||
public class CertDescriptor {
|
||||
protected static final Log log = LogFactory.getLog(CertDescriptor.class);
|
||||
/** 证书容器,存储对商户请求报文签名私钥证书. */
|
||||
private KeyStore keyStore = null;
|
||||
|
||||
/** 验签中级证书 */
|
||||
private X509Certificate publicKeyCert = null;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 通过证书路径初始化为公钥证书
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
private static X509Certificate initCert(String path) {
|
||||
X509Certificate encryptCertTemp = null;
|
||||
CertificateFactory cf = null;
|
||||
FileInputStream in = null;
|
||||
try {
|
||||
cf = CertificateFactory.getInstance("X.509", "BC");
|
||||
in = new FileInputStream(path);
|
||||
encryptCertTemp = (X509Certificate) cf.generateCertificate(in);
|
||||
// 打印证书加载信息,供测试阶段调试
|
||||
log.warn("[" + path + "][CertId="
|
||||
+ encryptCertTemp.getSerialNumber().toString() + "]");
|
||||
} catch (CertificateException e) {
|
||||
log.error("InitCert Error", e);
|
||||
} catch (FileNotFoundException e) {
|
||||
log.error("InitCert Error File Not Found", e);
|
||||
} catch (NoSuchProviderException e) {
|
||||
log.error("LoadVerifyCert Error No BC Provider", e);
|
||||
} finally {
|
||||
if (null != in) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
log.error(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
return encryptCertTemp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过keyStore 获取私钥签名证书PrivateKey对象
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public PrivateKey getSignCertPrivateKey() {
|
||||
try {
|
||||
Enumeration<String> aliasenum = keyStore.aliases();
|
||||
String keyAlias = null;
|
||||
if (aliasenum.hasMoreElements()) {
|
||||
keyAlias = aliasenum.nextElement();
|
||||
}
|
||||
PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyAlias,
|
||||
"SDKConfig.getConfig().getSignCertPwd()".toCharArray());
|
||||
return privateKey;
|
||||
} catch (KeyStoreException e) {
|
||||
log.error("getSignCertPrivateKey Error", e);
|
||||
return null;
|
||||
} catch (UnrecoverableKeyException e) {
|
||||
log.error("getSignCertPrivateKey Error", e);
|
||||
return null;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
log.error("getSignCertPrivateKey Error", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 配置的签名私钥证书certId
|
||||
*
|
||||
* @return 证书的物理编号
|
||||
*/
|
||||
public String getSignCertId() {
|
||||
try {
|
||||
Enumeration<String> aliasenum = keyStore.aliases();
|
||||
String keyAlias = null;
|
||||
if (aliasenum.hasMoreElements()) {
|
||||
keyAlias = aliasenum.nextElement();
|
||||
}
|
||||
X509Certificate cert = (X509Certificate) keyStore
|
||||
.getCertificate(keyAlias);
|
||||
return cert.getSerialNumber().toString();
|
||||
} catch (Exception e) {
|
||||
log.error("getSignCertId Error", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 将签名私钥证书文件读取为证书存储对象
|
||||
*
|
||||
* @param signCertPath
|
||||
* 证书文件名
|
||||
* @param signCertPwd
|
||||
* 证书密码
|
||||
* @param signCertType
|
||||
* 证书类型
|
||||
*/
|
||||
public void initPrivateSignCert(String signCertPath, String signCertPwd, String signCertType) {
|
||||
|
||||
if (null != keyStore) {
|
||||
keyStore = null;
|
||||
}
|
||||
try {
|
||||
keyStore = getKeyInfo(signCertPath,
|
||||
signCertPwd,signCertType);
|
||||
log.info("InitSignCert Successful. CertId=["
|
||||
+ getSignCertId() + "]");
|
||||
} catch (IOException e) {
|
||||
log.error("InitSignCert Error", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将签名私钥证书文件读取为证书存储对象
|
||||
*
|
||||
* @param pfxkeyfile
|
||||
* 证书文件名
|
||||
* @param keypwd
|
||||
* 证书密码
|
||||
* @param type
|
||||
* 证书类型
|
||||
* @return 证书对象
|
||||
* @throws IOException
|
||||
*/
|
||||
private KeyStore getKeyInfo(String pfxkeyfile, String keypwd,
|
||||
String type) throws IOException {
|
||||
log.warn("加载签名证书==>" + pfxkeyfile);
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
KeyStore ks = KeyStore.getInstance(type, "BC");
|
||||
log.warn("Load RSA CertPath=[" + pfxkeyfile + "],Pwd=["+ keypwd + "],type=["+type+"]");
|
||||
fis = new FileInputStream(pfxkeyfile);
|
||||
char[] nPassword = null;
|
||||
nPassword = null == keypwd || "".equals(keypwd.trim()) ? null: keypwd.toCharArray();
|
||||
if (null != ks) {
|
||||
ks.load(fis, nPassword);
|
||||
}
|
||||
return ks;
|
||||
} catch (Exception e) {
|
||||
log.error("getKeyInfo Error", e);
|
||||
return null;
|
||||
} finally {
|
||||
if(null!=fis)
|
||||
fis.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 通过keystore获取私钥证书的certId值
|
||||
* @param keyStore
|
||||
* @return
|
||||
*/
|
||||
private String getCertIdIdByStore(KeyStore keyStore) {
|
||||
Enumeration<String> aliasenum = null;
|
||||
try {
|
||||
aliasenum = keyStore.aliases();
|
||||
String keyAlias = null;
|
||||
if (aliasenum.hasMoreElements()) {
|
||||
keyAlias = aliasenum.nextElement();
|
||||
}
|
||||
X509Certificate cert = (X509Certificate) keyStore
|
||||
.getCertificate(keyAlias);
|
||||
return cert.getSerialNumber().toString();
|
||||
} catch (KeyStoreException e) {
|
||||
log.error("getCertIdIdByStore Error", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用模和指数生成RSA公钥 注意:此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同
|
||||
*
|
||||
* @param modulus
|
||||
* 模
|
||||
* @param exponent
|
||||
* 指数
|
||||
* @return
|
||||
*/
|
||||
private 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 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配置路径 加载敏感信息加密证书
|
||||
*/
|
||||
public void initPublicCert(String certPath) {
|
||||
if (!StringUtils.isEmpty(certPath)) {
|
||||
publicKeyCert = initCert(certPath);
|
||||
log.info("Load MiddleCert Successful");
|
||||
} else {
|
||||
log.info("WARN: acpsdk.middle.path is empty");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 从配置文件acp_sdk.properties中获取验签公钥使用的中级证书
|
||||
* @return
|
||||
*/
|
||||
public X509Certificate getPublicCert() {
|
||||
return publicKeyCert;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取证书的CN
|
||||
* @param aCert
|
||||
* @return
|
||||
*/
|
||||
private 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 证书文件过滤器
|
||||
*
|
||||
*/
|
||||
static class CerFilter implements FilenameFilter {
|
||||
public boolean isCer(String name) {
|
||||
if (name.toLowerCase().endsWith(".cer")) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public boolean accept(File dir, String name) {
|
||||
return isCer(name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -121,7 +121,7 @@ public enum SignUtils {
|
||||
* @return 去掉空值与签名参数后的新签名,拼接后字符串
|
||||
*/
|
||||
public static String parameterText(Map parameters, String separator) {
|
||||
return parameterText(parameters, separator, "sign", "key", "sign_type");
|
||||
return parameterText(parameters, separator, "signature", "sign", "key", "sign_type");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,6 +5,7 @@ import javax.crypto.Cipher;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
@@ -47,22 +48,22 @@ public class RSA{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* RSA签名
|
||||
* @param content 待签名数据
|
||||
* @param privateKey 私钥
|
||||
* @param signAlgorithms 签名算法
|
||||
* @param characterEncoding 编码格式
|
||||
* @return 签名值
|
||||
*/
|
||||
public static String sign(byte[] content,PrivateKey privateKey) {
|
||||
public static String sign(String content, PrivateKey privateKey, String signAlgorithms, String characterEncoding) {
|
||||
try {
|
||||
|
||||
java.security.Signature signature = java.security.Signature.getInstance(privateKey.getAlgorithm());
|
||||
|
||||
java.security.Signature signature = java.security.Signature.getInstance(signAlgorithms);
|
||||
signature.initSign(privateKey);
|
||||
signature.update(content);
|
||||
|
||||
signature.update(content.getBytes(characterEncoding));
|
||||
byte[] signed = signature.sign();
|
||||
|
||||
return Base64.encode(signed);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -71,6 +72,7 @@ public class RSA{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* RSA签名
|
||||
* @param content 待签名数据
|
||||
@@ -82,6 +84,17 @@ public class RSA{
|
||||
return sign(content, privateKey, SIGN_ALGORITHMS, characterEncoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* RSA签名
|
||||
* @param content 待签名数据
|
||||
* @param privateKey 私钥
|
||||
* @param characterEncoding 编码格式
|
||||
* @return 签名值
|
||||
*/
|
||||
public static String sign(String content, PrivateKey privateKey ,String characterEncoding){
|
||||
return sign(content, privateKey, SIGN_ALGORITHMS, characterEncoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* RSA验签名检查
|
||||
* @param content 待签名数据
|
||||
@@ -105,6 +118,27 @@ public class RSA{
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* RSA验签名检查
|
||||
* @param content 待签名数据
|
||||
* @param sign 签名值
|
||||
* @param publicKey 公钥
|
||||
* @param signAlgorithms 签名算法
|
||||
* @param characterEncoding 编码格式
|
||||
* @return 布尔值
|
||||
*/
|
||||
public static boolean verify(String content, String sign, PublicKey publicKey, String signAlgorithms, String characterEncoding){
|
||||
try {
|
||||
java.security.Signature signature = java.security.Signature.getInstance(signAlgorithms);
|
||||
signature.initVerify(publicKey);
|
||||
signature.update( content.getBytes(characterEncoding) );
|
||||
return signature.verify( Base64.decode(sign) );
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* RSA验签名检查
|
||||
* @param content 待签名数据
|
||||
@@ -117,7 +151,20 @@ public class RSA{
|
||||
|
||||
return verify(content, sign, publicKey, SIGN_ALGORITHMS, characterEncoding);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* RSA验签名检查
|
||||
* @param content 待签名数据
|
||||
* @param sign 签名值
|
||||
* @param publicKey 公钥
|
||||
* @param characterEncoding 编码格式
|
||||
* @return 布尔值
|
||||
*/
|
||||
public static boolean verify(String content, String sign, PublicKey publicKey, String characterEncoding){
|
||||
return verify(content, sign, publicKey, SIGN_ALGORITHMS, characterEncoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密
|
||||
* @param content 密文
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package com.egzosn.pay.common.util.sign.encrypt;
|
||||
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
|
||||
public class RSA2 {
|
||||
|
||||
@@ -16,6 +17,16 @@ public class RSA2 {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* RSA签名
|
||||
* @param content 待签名数据
|
||||
* @param privateKey 私钥
|
||||
* @param characterEncoding 编码格式
|
||||
* @return 签名值
|
||||
*/
|
||||
public static String sign(String content, PrivateKey privateKey ,String characterEncoding){
|
||||
return RSA.sign(content, privateKey, SIGN_SHA256RSA_ALGORITHMS, characterEncoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* RSA验签名检查
|
||||
@@ -29,7 +40,21 @@ public class RSA2 {
|
||||
|
||||
return RSA.verify(content, sign, publicKey, SIGN_SHA256RSA_ALGORITHMS, characterEncoding );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* RSA验签名检查
|
||||
* @param content 待签名数据
|
||||
* @param sign 签名值
|
||||
* @param publicKey 公钥
|
||||
* @param characterEncoding 编码格式
|
||||
* @return 布尔值
|
||||
*/
|
||||
public static boolean verify(String content, String sign, PublicKey publicKey, String characterEncoding){
|
||||
return RSA.verify(content, sign, publicKey, SIGN_SHA256RSA_ALGORITHMS, characterEncoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密
|
||||
* @param content 密文
|
||||
|
||||
Reference in New Issue
Block a user