银联基础完成

This commit is contained in:
egan
2017-12-10 22:29:53 +08:00
parent bf8c4462d7
commit 13ad1545b6
12 changed files with 578 additions and 1509 deletions

View File

@@ -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();
}
}
}

View File

@@ -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

View File

@@ -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);
}
}
}

View File

@@ -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");
}
/**

View File

@@ -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 密文

View File

@@ -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 密文