package com.tax.token.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

public class EncryptUtil {

	protected static Logger logger = LoggerFactory.getLogger(EncryptUtil.class);

	public static final String MD2 = "MD2";

	public static final String MD5 = "MD5";

	public static final String SHA = "SHA";

	public static final String SHA_256 = "SHA-256";

	public static final String SHA_384 = "SHA-384";

	public static final String SHA_512 = "SHA-512";

	public static final String KEY = "1a3c5e7g8h6f4d2b";
	
	public static final String CKKEY = "2a3c5e7g1h6f4d2b";

    public static final String FKEY = "T1C2K3";

	public static final String KEY_ALGORITHM = "RSA";

	public static final String SIGNATURE_ALGORITHM = "SHA1withRSA";

	private static final int MAX_DECRYPT_BLOCK = 128; // 128

	/**
	 * 
	 * BASE64解密
	 * 
	 * 
	 * 
	 * @param key
	 * 
	 * @return
	 * 
	 * @throws Exception
	 * 
	 */

	public static byte[] decryptBASE64(String key) throws Exception {

		return (new BASE64Decoder()).decodeBuffer(key);

	}

	public static String byteToString(byte[] byteArray) throws UnsupportedEncodingException {

		return new String(byteArray);

	}

	/**
	 * 
	 * BASE64加密
	 * 
	 * 
	 * 
	 * @param key
	 * 
	 * @return
	 * 
	 * @throws Exception
	 * 
	 */

	public static String encryptBASE64(byte[] key) throws Exception {

		return StringEncryptUtil.trimEnter((new BASE64Encoder()).encodeBuffer(key));

	}

	/**
	 * 
	 * 不可逆加密
	 * 
	 * 
	 * 
	 * @param sourceStr
	 *            需要加密目标字符串
	 * 
	 * @param algorithmsName
	 *            算法名称(如:MD2,MD5,SHA-1,SHA-256)
	 * 
	 * @return
	 * 
	 */

	public static String encrypt(String sourceStr, String algorithmsName) {

		String encryptString = "";

		MessageDigest md;

		try {

			md = MessageDigest.getInstance(algorithmsName);

			// 使用指定byte[]更新摘要

			md.update(sourceStr.getBytes());

			// 完成计算，返回结果数组

			byte[] b = md.digest();

			encryptString = StringEncryptUtil.byteArrayToHex(b);

			encryptString = StringEncryptUtil.trimEnter(encryptString);

		} catch (NoSuchAlgorithmException e) {

			e.printStackTrace();

		}

		return encryptString;

	}

	/*
	 * 
	 * ***********************************************************
	 * 
	 * ***********************************************************
	 * 
	 * 一下为AES加密解密方法
	 * 
	 * 
	 * 
	 * ***********************************************************
	 * 
	 * ***********************************************************
	 * 
	 */

	/**
	 * 
	 * 转换密钥
	 * 
	 * @param key
	 * 
	 * @return
	 * 
	 * @throws Exception
	 * 
	 */

	private static Key toKey(String key) throws Exception {

		SecretKey secretKey = new SecretKeySpec(key.getBytes(), "AES");

		return secretKey;

	}

	/**
	 * 
	 * 对数据进行解密
	 * 
	 * @param data
	 * 
	 * @param key
	 * 
	 * @return
	 * 
	 * @throws Exception
	 * 
	 */

	public static String decryptAes(String data, String key) throws Exception {

		Key k = toKey(key);

		Cipher cipher = Cipher.getInstance("AES/CBC/ISO10126Padding");

		IvParameterSpec iv = new IvParameterSpec(key.getBytes());

		cipher.init(Cipher.DECRYPT_MODE, k, iv);

		return new String(cipher.doFinal(decryptBASE64(data)));

	}

	/**
	 * 
	 * 对数据进行加密
	 * 
	 * @param data
	 * 
	 * @param key
	 * 
	 * @return
	 * 
	 * @throws Exception
	 * 
	 */

	public static String encryptAes(String data, String key) throws Exception {

		Key k = toKey(key);

		IvParameterSpec iv = new IvParameterSpec(key.getBytes());

		Cipher cipher = Cipher.getInstance("AES/CBC/ISO10126Padding");

		cipher.init(Cipher.ENCRYPT_MODE, k, iv);

		return encryptBASE64((cipher.doFinal(data.getBytes())));

	}

	/*
	 * 
	 * ***********************************************************
	 * 
	 * ***********************************************************
	 * 
	 * 以下为RSA加密解密方法
	 * 
	 * 
	 * 
	 * ***********************************************************
	 * 
	 * ***********************************************************
	 * 
	 */

	/**
	 * 
	 * 用私钥解密
	 * @param data
	 * @throws Exception
	 * 
	 */

	public static String decryptRsa(String data)

	throws Exception {

		// 获取私钥

		// String key =
		// String.valueOf(Const.initPramsMap.get(Const.RSA_PRIVATE_KEY));

		String key = "";

		// 对密钥解密

		byte[] keyBytes = decryptBASE64(key);

		PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);

		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

		Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);

		Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

		cipher.init(Cipher.DECRYPT_MODE, privateK);

		byte[] dataByte = decryptBASE64(data);

		int inputLen = dataByte.length;

		ByteArrayOutputStream out = new ByteArrayOutputStream();

		int offSet = 0;

		byte[] cache;

		int i = 0;

		// 117限制，分段解密

		while (inputLen - offSet > 0) {

			if (inputLen - offSet > MAX_DECRYPT_BLOCK) {

				cache = cipher.doFinal(dataByte, offSet, MAX_DECRYPT_BLOCK);

			} else {

				cache = cipher.doFinal(dataByte, offSet, inputLen - offSet);

			}

			out.write(cache, 0, cache.length);

			i++;

			offSet = i * MAX_DECRYPT_BLOCK;

		}

		byte[] decryptedData = out.toByteArray();

		out.close();

		return StringEncryptUtil.trimEnter(byteToString(decryptedData));

	}

	/**
	 * 获取公钥
	 * @return
	 * @throws Exception
	 */

	public static String getPublicKey() {

		// return Const.initPramsMap.get(Const.RSA_PUBLIC_KEY);

		return "";

	}

	/**
	 * 
	 * 用私钥对信息生成数字签名
	 * 
	 * 
	 * 
	 * @param data
	 * 
	 *            加密数据
	 * 
	 * @param privateKey
	 * 
	 *            私钥
	 * 
	 * @param encode
	 * 
	 *            签名字符串编码
	 * 
	 * 
	 * 
	 * @return
	 * 
	 * @throws Exception
	 * 
	 */

	public static String sign(String data, String privateKey, String encode) throws Exception {

		// 解密由base64编码的私钥

		byte[] keyBytes = decryptBASE64(privateKey);

		// 构造PKCS8EncodedKeySpec对象

		PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);

		// KEY_ALGORITHM 指定的加密算法

		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

		// KEY_ALGORITHM 指定的加密算法

		PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);

		// 用私钥对信息生成数字签名

		Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);

		signature.initSign(priKey);

		signature.update(data.getBytes(encode));

		// return StringUtil.byteArrayToHex(signature.sign());

		return encryptBASE64(signature.sign());

	}

	/**
	 * 
	 * 校验数字签名
	 * 
	 * 
	 * 
	 * @param data
	 * 
	 *            加密数据
	 * 
	 * @param publicKey
	 * 
	 *            公钥
	 * 
	 * @param sign
	 * 
	 *            数字签名
	 * 
	 * @param encode
	 * 
	 *            签名字符串编码
	 * 
	 * 
	 * 
	 * @return 校验成功返回true 失败返回false
	 * 
	 * @throws Exception
	 * 
	 * 
	 * 
	 */

	public static boolean verify(String data, String publicKey, String sign, String encode)

	throws Exception {

		// 解密由base64编码的公钥

		byte[] keyBytes = decryptBASE64(publicKey);

		// 构造X509EncodedKeySpec对象

		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);

		// KEY_ALGORITHM 指定的加密算法

		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

		// 取公钥匙对象

		PublicKey pubKey = keyFactory.generatePublic(keySpec);

		Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);

		signature.initVerify(pubKey);

		signature.update(data.getBytes(encode));

		// 验证签名是否正常

		// return signature.verify(StringUtil.hexToBytes(sign));

		return signature.verify(decryptBASE64(sign));

	}

	/**
	 * 
	 * 生成密钥对
	 * 
	 * 
	 * 
	 * @return
	 * 
	 * @throws Exception
	 * 
	 */

	public static Map<String, String> genRsaKey() throws Exception {

		KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);

		keyPairGen.initialize(1024);

		KeyPair keyPair = keyPairGen.generateKeyPair();

		// 生成公钥

		RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();

		// 生成私钥

		RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

		Map<String, String> keyMap = new HashMap<String, String>();

		keyMap.put("public", StringEncryptUtil.trimEnter(encryptBASE64(publicKey.getEncoded())));

		keyMap.put("private", StringEncryptUtil.trimEnter(encryptBASE64(privateKey.getEncoded())));

		return keyMap;
	}

	public static String encryptAesCk(String data) {
		if(!StringEncryptUtil.isBlank(data)) {
			try {
				data = FKEY + encryptAes(data, CKKEY);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return data;
	}

	public static String decryptAesCk(String data) {
		if(!StringEncryptUtil.isBlank(data)) {
			try {
				data = decryptAes(data.substring(6, data.length()), CKKEY);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return data;
	}


	public static void main(String[] args) {
		try {
			String jym = "x_host_key=1838dc43ca7-257e7e0afea57d7f8d2f17dbd8442caa89d0bdc5;dzfp-ssotoken=56483d7ef35748ecab06fadccb17555b;oauth2_referer=etax.shanghai.chinatax.gov.cn;JSESSIONID=A07FBCE32678F4958227B8276CD5466D;SSO_SECURITY_CHECK_TOKEN=ed65bf66211c4dbdb572e98e1ec71d19;";
			String jmjym = EncryptUtil.encryptAesCk(jym);
			System.out.println(jmjym);
			System.out.println(EncryptUtil.decryptAesCk("T1C2K3y8C5PrmwN0+VGXnyf6d3p/m6jsxF3JLyyZRFI7xjF/Jtpb5xu5uL3xRccLddHlhvA8nXfvJIOe0F3VYz4VYDfoTP8VhJ4fyjWFG0dJdkc14hvCC6UjjMnt9fdUWslqs7V46H0vjMWyXOQwHxiq+aSuWWu9/pgd+H0MmrbNUXazFxDoBCEz0245LCChs0wKZZeGlNKGLx3IOjvcfjTrh8ZINeB28RAy2JvgS3Ar6dUW852p9Du7AADT7NktzRlnf04rErvvgDtEo+dES0mXs+xFSnfLs8k6EpWHznmR+oMhrtT5gmN2DkEGVCIjMdW1tvwglzqjLwCJJJfWqe9Psq9Beo7s2/vr7MwaTi2yxpYjpg6k8V8XZmnJ/K1eyeRm1KxMlBuLclRRUtZCMBfkbS/A/1ANYjnOmu51+W13wKd/AiMUcFSyR2+/mX2Sbcgjyt+FhvUryOHYSsXtaCGIgpCd2kh39qtApcGr1iGcUWC/k2BDfFpqviR/V9HYbzRW//riy52j4YgVUqtWqoAHgfY4CJBNgeUzgjnp+PqeIVNIcjM9rdr/hvX4vuvFOPUvKkown77QbyYeCYg0wurY3TLcIRkprP+dPyINsyoKL0EUrPna+SpXehj98ux5yj14Q9Wq2kpmLQa7Tcd8wMm5qXMQ=="));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
