package com.bcxin.ins.third.gyx.taibao.util;

import com.bcxin.ins.util.ConstProp;
import com.bcxin.ins.util.GlobalResources;
import com.sun.org.apache.xml.internal.security.utils.Base64;
//import org.junit.jupiter.api.Test;

import java.io.StringWriter;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * <p>
 * RSA公钥/私钥/签名工具包
 * </p>
 * <p>
 * 支持分段加密，扩展了加密明文的长度
 * </p>
 * <p>
 * 字符串格式的密钥在未在特殊说明情况下都为BASE64编码格式<br/>
 * 由于非对称加密速度极其缓慢，一般文件不使用它来加密而是使用对称加密，<br/>
 * 非对称加密算法可以用来对对称加密的密钥加密，这样保证密钥的安全也就保证了数据的安全
 * </p>
 * <p>
 * 1024位的证书，加密时最大支持117个字节，解密时为128；<br/>
 * 2048位的证书，加密时最大支持245个字节，解密时为256。
 * </p>
 * 
 * @author zxf 2018年03月06日
 * 
 */
public class TbRsaUtils {

	/**
	 * 加密算法RSA
	 */
	public static final String KEY_ALGORITHM = "RSA";

	/**
	 * 签名算法
	 */
	public static final String SIGNATURE_ALGORITHM = "SHA256WITHRSA";

	/**
	 * 获取太保公钥的key
	 */
	private static String TB_PUBLIC_KEY = ConstProp.BLANK_CHAR;

	/**
	 * 获取公钥的key
	 */
	private static String PUBLIC_KEY = ConstProp.BLANK_CHAR;

	/**
	 * 获取私钥的key
	 */
	private static String PRIVATE_KEY = ConstProp.BLANK_CHAR;

	public static void setKeys(boolean isTest){
		if(isTest){//测试环境
			TB_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNY9kYwaDQQEWTxAXo5fP3p+8bGlhUladJhvN/Gv/auHcHjbHtNWck6tPpjxxcQFK1Sk38YZjURusIU2XURVF+pVv6jBSyU/VoQ0nwEnS4CVkvpex9DaruNILz0YmjMX/cbGccvkSbOkPM+/gn/ajJTmWqZNgkqbTmUExXWrrZuQIDAQAB";
			PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJW/pMRELS0+et8f9EzC+1miJq6yL6GZsxJSPVfK0BM9R9WGoAQDgl3IvJoSSbHtqWNJI+wPY4BVaRSCU33fTgu+/yPe8z0ktKqlgU0fiLezZ+TPXE+fnS16rw/uWM4ej7yVWHzJJNlBa+hIdW1/NISHixMq/eKo5/PVOM/NCnmwIDAQAB";
			PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIlb+kxEQtLT563x/0TML7WaImrrIvoZmzElI9V8rQEz1H1YagBAOCXci8mhJJse2pY0kj7A9jgFVpFIJTfd9OC77/I97zPSS0qqWBTR+It7Nn5M9cT5+dLXqvD+5Yzh6PvJVYfMkk2UFr6Eh1bX80hIeLEyr94qjn89U4z80KebAgMBAAECgYBPFjxJSUxIY2YTyzA1BnO51iNW+EfNRI0MgNvfAcgC1zrTaOKvfkpV0mRSFYwkHGGy9lX199hMbRZo0+dKAWwKWSueQe9vAXY7LXHh1cQ10QExEYPYfhIveXrPBlN2BYEwcK9hrCG/MfHgo5vjzw3+o+gMfznGq4cnQlSe9KFicQJBAMXUyxWPvCS6AkYP6sX3ogiIOZMbTQE9HRTo0HjXWuESlAJ8TwtUNeSQKx2U8nhg17eg4jIUgTiNqxTfb0QsOdcCQQCxv1L5VRu0GWY3xPy+VhJZaLcJhbt2dbVQtjXYjLUK+ooC55anP7mvHIFtWQCVPMhlfIeKh8+zQ09TBPB2Fe/dAkAazvBKVrUHQRGnzuZgt2MExvkOX0e7ID39pGMDzSMqlurpv1Cy11GKTKMbGiEVgQIahzm/0ZmFQWVqqbCZS2j3AkEAl2B/w8SN0XYILdrf/SHEgszBhaSVIK/ieRiVBxXeYbk5rHubPFjzRIUcXQn9ixu292d076/2XY8nkWaVe5v3KQJANiirFqUH10aiq9klSUKgt17mXZ9LSapeyOahAA5h3XbY+GrfZoteawDCqIrPI6PWJWYvKqo238zwZYgnvWRTLg==";
		}else{//生产环境
			TB_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCkiD4gBFaB8Az+kUFdhDDjlZp6fgKKCbGD3Z+1DG1J9bujvXUoLCz8atOtNrTrWizu+TcGAeXJRo138Pgp06Bp/ixAlRnFkKmhqhaiCBHHMRvdxuaulscD6IGNW++rQlKO3jRH9ma1fVf8JkMLDkSA7vMRR4A8vj+5+zqf+chkYQIDAQAB";
			PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCkQ72mefboDBMGfKL8Z2T2iNXqZceHhmARrae+f1fJcfBEosHJiaLsqAXcTFtEQAqcCyFy+wKe8LQqHvxpoBm15TWWYx0rxPqxsWHvjlzgXU8wN+dyYxRf8oRUqBNnjPwP8DUfcsapaGGaWg79DFkn5q7FpyGocnYBOvf+C3p3QwIDAQAB";
			PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKRDvaZ59ugMEwZ8ovxnZPaI1eplx4eGYBGtp75/V8lx8ESiwcmJouyoBdxMW0RACpwLIXL7Ap7wtCoe/GmgGbXlNZZjHSvE+rGxYe+OXOBdTzA353JjFF/yhFSoE2eM/A/wNR9yxqloYZpaDv0MWSfmrsWnIahydgE69/4LendDAgMBAAECgYEAmbwsitorExH53GBZyhCalYGLc0y+aUCCOQllrQxRhN92F0acR5rhOMwob/2mjUHCrDhendX+pfJxK9rEMbb9V5L6lq+wZPtv7QVMtNaOKU8oJsVjNAMIiazd/9dB6qhMIUiQwnz4RkU8iEheMyM0CSsuM0YsjdkCCdEA+YNLzsECQQDwPsMWRP9SiGZWlvS9mPrt95Ea3W6HhPaAKY/76eW8NmP+tXbr6XmpubBvFQfbh02ZwDKeEgbPXffMROAtHi1dAkEArwlqpZk22URH/m3pznLknIM8wdfbkD9BsLHc27OzH4KvXOfBT8JcZbofHu/1pv1ogtvzA1GXzBjcHBTfJQZNHwJAPbiSHDWLtuNuD07m/5K+3MYelF1RGSXywkhrQlf7+peqpvRt4fvwkscu6croYuDm8dor5upQr5O/ps4HHfBDzQJAZw5KRjnRO1aidMDOGgk3ZJc4XID0+xbjXF88Q/anjfPpv++Lt6Qdtp9A13w8zBcDQ5iwmdGeaEJyxe3b+/abzQJAKQVUO4w71hERDvLk79IdyvnklLQBztkHebFa50PCuQP5aBZWECmkeFivnDbQbKtgOFxqxy0hCWakGzXt15eDdA==";
		}
	}

//	@Test
	public void testVerify() throws Exception {
		/*//初始化公钥私钥
		setKeys(false);
		//获取请求报文
		String text = ResourceGroovyMethods.getText(new File(""));
		String data = text.substring(text.indexOf("<request>") + "<request>".length(), text.indexOf("</request>"));
		String dataEncode = Base64.encode(data.getBytes("UTF-8"));
		System.err.println(dataEncode);
		byte[] signBytes = sign(dataEncode.replace("\n", "").getBytes(), Base64.decode(privateKey), algorithm);
		String sign = Base64.encode(signBytes, Integer.MAX_VALUE);
		System.err.println(sign);
		StringWriter sw = new StringWriter();
		sw.append("<document><signature>").append(sign).append("</signature><request>");
		sw.append(data);
		sw.append("</request></document>");
		System.out.println(sw.toString());
		dataEncode = Base64.encode(data.getBytes("UTF-8"));

		boolean verify = verify(dataEncode.replace("\n", "").getBytes(), Base64.decode(sign),
				Base64.decode(publicKey), algorithm);
		System.out.println(verify);
		//调用
		HttpClient client = new HttpClient();
		PostMethod pm = new PostMethod("");
		pm.setRequestEntity(new StringRequestEntity(sw.toString(), "text/xml", "UTF-8"));
		client.executeMethod(pm);
		System.out.println(pm.getResponseBodyAsString());*/

	}

	/**
	 * <b> 对报文生成sign并加入节点 </b>
	 * @author ZXF
	 * @create 2018/03/06 0006 10:03
	 * @version
	 * @注意事项 </b>
	 */
	public static String appendSign(String text) throws Exception{
		//初始化key
		setKeys(GlobalResources.IS_TEST_ENVI);
		String data = text.substring(text.indexOf("<request>") + "<request>".length(), text.indexOf("</request>"));
		String dataEncode = Base64.encode(data.getBytes("UTF-8"));
		System.err.println(dataEncode);
		byte[] signBytes = sign(dataEncode.replace("\n", "").getBytes(), Base64.decode(PRIVATE_KEY));
		String sign = Base64.encode(signBytes, Integer.MAX_VALUE);
		System.err.println(sign);
		StringWriter sw = new StringWriter();
		sw.append("<document><signature>").append(sign).append("</signature><request>");
		sw.append(data);
		sw.append("</request></document>");
		System.out.println(sw.toString());
		dataEncode = Base64.encode(data.getBytes("UTF-8"));

		boolean verify = verify(dataEncode.replace("\n", "").getBytes(), Base64.decode(sign),
				Base64.decode(PUBLIC_KEY));
		System.out.println(verify);
		if(verify){
			return sw.toString();
		}
		return ConstProp.BLANK_CHAR;
	}

	/**
	 * <b> 对返回报文生成sign并加入节点 </b>
	 * @author ZXF
	 * @create 2018/03/06 0006 10:03
	 * @version
	 * @注意事项 </b>
	 */
	public static String appendSignResult(String text) throws Exception{
		//初始化key
		setKeys(GlobalResources.IS_TEST_ENVI);
		String data = text.substring(text.indexOf("<response>"), text.indexOf("</response>") + "</response>".length());
		System.err.println(data);
		String dataEncode = Base64.encode(data.getBytes("UTF-8"));
		System.err.println(dataEncode);
		byte[] signBytes = sign(dataEncode.replace("\n", "").getBytes(), Base64.decode(PRIVATE_KEY));
		String sign = Base64.encode(signBytes, Integer.MAX_VALUE);
		System.err.println(sign);
		StringWriter sw = new StringWriter();
		sw.append("<document><signature>").append(sign).append("</signature>");
		sw.append(data);
		sw.append("</document>");
		System.out.println(sw.toString());
		dataEncode = Base64.encode(data.getBytes("UTF-8"));

		boolean verify = verify(dataEncode.replace("\n", "").getBytes(), Base64.decode(sign),
				Base64.decode(PUBLIC_KEY));
		System.out.println(verify);
		if(verify){
			return sw.toString();
		}
		return ConstProp.BLANK_CHAR;
	}

	/**
	 * <b> 用太保公钥校验sign是否匹配 </b>
	 * @author ZXF
	 * @create 2018/03/06 0006 10:03
	 * @version
	 * @注意事项 </b>
	 */
	public static boolean verifySign(String text) throws Exception{
		//初始化key
		setKeys(GlobalResources.IS_TEST_ENVI);
		String data = text.substring(text.indexOf("<response>"), text.indexOf("</response>") + "</response>".length());
		System.err.println(data);
		String dataEncode = Base64.encode(data.getBytes("UTF-8"));
		System.err.println(dataEncode);
		String sign = text.substring(text.indexOf("<signature>") + "<signature>".length(), text.indexOf("</signature>")/* - "</signature>".length()*/);
		System.err.println(sign);
		dataEncode = Base64.encode(data.getBytes("UTF-8"));
		boolean verify = verify(dataEncode.replace("\n", "").getBytes(), Base64.decode(sign),
				Base64.decode(TB_PUBLIC_KEY));
		return verify;
	}

	/**
	 * <b> (对支付结果，承保结果)用太保公钥校验sign是否匹配 </b>
	 * @author ZXF
	 * @create 2018/03/06 0006 10:03
	 * @version
	 * @注意事项 </b>
	 */
	public static boolean verifyResultSign(String text) throws Exception{
		//初始化key
		setKeys(GlobalResources.IS_TEST_ENVI);
		String data = text.substring(text.indexOf("<request>") + "<request>".length(), text.indexOf("</request>"));
		System.err.println(data);
		String dataEncode = Base64.encode(data.getBytes("UTF-8"));
		System.err.println(dataEncode);
		String sign = text.substring(text.indexOf("<signature>") + "<signature>".length(), text.indexOf("</signature>")/* - "</signature>".length()*/);
		System.err.println(sign);
		dataEncode = Base64.encode(data.getBytes("UTF-8"));
		boolean verify = verify(dataEncode.replace("\n", "").getBytes(), Base64.decode(sign),
				Base64.decode(PUBLIC_KEY));
		return verify;
	}

	/**
	 * <b> 验签 </b>
	 * @author ZXF
	 * @create 2018/03/06 0006 10:04
	 * @version
	 * @注意事项 </b>
	 */
	private static boolean verify(final byte[] text, final byte[] signedText, final byte[] publicKeyData) throws GeneralSecurityException {
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyData);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		PublicKey publicKey = keyFactory.generatePublic(keySpec);
		Signature signatureChecker = Signature.getInstance(SIGNATURE_ALGORITHM);
		signatureChecker.initVerify(publicKey);
		signatureChecker.update(text);
		return signatureChecker.verify(signedText);
	}

	/**
	 * <p>
	 * 用私钥对信息生成数字签名
	 * </p>
	 *
	 * @param text
	 * @param privateKeyData
	 *
	 * @return
	 * @throws Exception
	 */
	private static byte[] sign(final byte[] text, final byte[] privateKeyData) throws Exception {
		PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyData);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
		Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
		signature.initSign(privateK);
		signature.update(text);
		return signature.sign();
	}

}