/**
 *
 * 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.jeequan.jeepay.thirdparty.channel.yspay.utils;

import cfca.sadk.org.bouncycastle.util.encoders.Base64Kit;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Enumeration;

@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class CertUtil {
	/** 证书容器. */
	private static KeyStore keyStore = null;

	/** 验证签名证书. */
	private static Certificate validateCert = null;

	/** 验证签名证书. KEYSTORE_TYPE-PKCS12 */
	private static final String KEYSTORE_TYPE = "PKCS12";

	/** 验证签名证书. CERTFACTORY_TYPE-PKCS12 */
	private static final String  CERTFACTORY_TYPE= "X.509";

	/**
	 * 加载签名证书
	 */
	public static KeyStore initSignCert(String pfxPath,String pfxPwd) throws Exception {
		if (null != keyStore) {
			keyStore = null;
		}
		try {
			// 默认存放的文件夹路径
			keyStore = getKeyInfo(pfxPath,pfxPwd, KEYSTORE_TYPE);
		} catch (IOException e) {
			e.printStackTrace();
			throw e;
		}
		return keyStore;
	}
	/**
	 * 将证书文件读取为证书存储对象
	 *
	 * @param pfxkeyfile
	 *            证书文件名
	 * @param keypwd
	 *            证书密码
	 * @param type
	 *            证书类型 ,以.pfx结尾用PKCS12
	 * @return 证书对象
	 * @throws IOException
	 */
	public static KeyStore getKeyInfo(String pfxkeyfile,String keypwd,String type) throws Exception {
		FileInputStream fis = null;
		try {

			KeyStore ks = null;
			ks = KeyStore.getInstance(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) {
			throw e;
		}finally{
			if(null!=fis){
				fis.close();
			}
		}
	}

	/**
	 * 获取签名证书私钥（单证书）
	 */
	public static PrivateKey getSignCertPrivateKey(String pfxPath,String pfxPwd)throws Exception {
		if(keyStore == null){
			keyStore = initSignCert(pfxPath,pfxPwd);
		}
		Enumeration<String> aliasenum = keyStore.aliases();
		String keyAlias = null;
		if (aliasenum.hasMoreElements()) {
			keyAlias = aliasenum.nextElement();
		}
		PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyAlias, pfxPwd.toCharArray());
		return privateKey;
	}

	/**
	 * 从指定目录书路径获取Certificate对象
	 * @return
	 */
	public static Certificate initValidateCertFromDir(String crtPath) throws Exception {
		CertificateFactory cf = null;
		FileInputStream in = null;
		try {
			cf = CertificateFactory.getInstance(CERTFACTORY_TYPE);
			in = new FileInputStream(crtPath);
			validateCert = cf.generateCertificate(in);
		} finally {
			if (null != in) {
				try {
					in.close();
				} catch (IOException e) {
					throw  e;
				}
			}
		}
		return validateCert;
	}

	/**
	 * 根据证书路径获取Certificate对象
	 */
	public static Certificate getValidateCert(String crtPath) throws Exception {
		log.info("Cert starts loading...[certPath is:"+crtPath+"]");
		if(validateCert != null){
			log.info("cert is already exists,don't need to load it");
			return validateCert;
		}
		return initValidateCertFromDir(crtPath);
	}

	/**
	 * 根据公钥字符串获取PublicKey对象
	 * @return
	 */
	public static PublicKey getPubKeyObj(String pubKey)throws Exception {
		java.security.spec.X509EncodedKeySpec bobPubKeySpec = new java.security.spec.X509EncodedKeySpec(Base64Kit.decode(pubKey));
		// RSA对称加密算法
		KeyFactory keyFactory;
		keyFactory = KeyFactory.getInstance("RSA");
		// 取公钥匙对象
        return keyFactory.generatePublic(bobPubKeySpec);
	}

	/**
	 * 根据私钥字符串获取PrivateKey对象
	 * @return
	 */
	public static PrivateKey getPriKeyObj(String priKeyStr) throws Exception {
		PrivateKey privateKey;
		PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64Kit.decode(priKeyStr));
		KeyFactory keyf = KeyFactory.getInstance("RSA");
		privateKey = keyf.generatePrivate(priPKCS8);
		return privateKey;
	}

	/**
	 * 获取私钥字符串根据私钥证书和密码
	 */
	public static String getPrivateKeyInfo(String privKeyFilePath,String privKeyPswd) throws Exception {
		KeyStore keyStore = KeyStore.getInstance( KEYSTORE_TYPE);
		FileInputStream fileInputStream = new FileInputStream(privKeyFilePath);
		char[] nPassword;
		if ((privKeyPswd == null) || privKeyPswd.trim().isEmpty()) {
			nPassword = null;
		} else {
			nPassword = privKeyPswd.toCharArray();
		}
		keyStore.load(fileInputStream, nPassword);
		fileInputStream.close();
		Enumeration<String> enumeration = keyStore.aliases();
		String keyAlias ="";
		if (enumeration.hasMoreElements()) {
			keyAlias = enumeration.nextElement();
		}
		PrivateKey priKey = (PrivateKey) keyStore.getKey(keyAlias, nPassword);
		return Base64Kit.toBase64String(priKey.getEncoded());
	}

	/**
	 * 获取公钥字符串 根据公钥证书
	 */
	public static String getPublicKeyInfo(String publicKeyPath) throws Exception {
		//获取X.509对象工厂
		CertificateFactory cf = CertificateFactory.getInstance(CERTFACTORY_TYPE);
		//通过文件流读取证书文件
		X509Certificate cert = (X509Certificate)cf.generateCertificate(Files.newInputStream(Paths.get(publicKeyPath)));
		//获取公钥对象
		PublicKey publicKey = cert.getPublicKey();
		return Base64Kit.toBase64String(publicKey.getEncoded());
	}
}
