package com.yd.util;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import java.io.*;
import java.security.*;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class EncryptUtil {
	private static final Log logger = LogFactory.getLog(EncryptUtil.class);
	private static final String HEX_CHARS = "0123456789abcdef";
	/**
	 * 加密
	 * @param source
	 * @return
	 */
	public static String encrypt(String source,String charSet) {
		if(CommonUtil.isNullOrBlank(source)){
			return null;
		}
		if(CommonUtil.isNullOrBlank(charSet)){
			charSet = "utf-8";
		}
	    try {  
	        MessageDigest md = MessageDigest.getInstance("MD5");  
	        try {
				md.update(source.getBytes(charSet));
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}  
	        byte b[] = md.digest();  
	        int i;  
	        StringBuffer buf = new StringBuffer("");  
	        for (int offset = 0; offset < b.length; offset++) {  
	            i = b[offset];  
	            if (i < 0){i += 256;}  
	            if (i < 16){buf.append("0");}  
	            buf.append(Integer.toHexString(i));  
	        }  
	        //32位加密  
	        return buf.toString();  
	        // 16位的加密  
	        //return buf.toString().substring(8, 24);  
	    } catch (NoSuchAlgorithmException e) {  
//	        e.printStackTrace();  
	        return null;  
	    }
	}
	
	public static String encryptLiberty(String str,String charSet) {
        if (CommonUtil.isNullOrBlank(str)){
            return null;
        }
        if(CommonUtil.isNullOrBlank(charSet)){
			charSet = "utf-8";
		}
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(str.getBytes(charSet));
            return byteArrayToHexString(md.digest());
        } catch (Exception e) {
//            System.out.println(e.getMessage());
            return null;
        }
    }

    public static String byteArrayToHexString(byte[] b) {
        String result = "";
        for (byte aB : b) {
            result += Integer.toString((aB & 0xff) + 0x100, 16).substring(1);
        }
        return result;
    }
    
    /**
     * SHA256WithRSA 加签
     * 
     * @param content
     * @param privateKey
     * @param charset
     * @return
     */
    public static String rsa256Sign(String content, String privateKey,String charset){
//    	org.apache.xml.security.utils.Base64 b = null;
    	try {
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			byte[] encodedKey = Base64.getDecoder().decode(privateKey);
			PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey);
			PrivateKey prikey = keyFactory.generatePrivate(keySpec);
			
			Signature signature = Signature.getInstance("SHA256WithRSA");
			signature.initSign(prikey);
			if(charset != null && !"".equals(charset)){
				signature.update(content.getBytes(charset));
			}else{
				signature.update(content.getBytes());
			}
			byte[] signed = signature.sign();
			
			return new String(Base64.getEncoder().encode(signed));
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (InvalidKeySpecException e){
			e.printStackTrace();
		} catch (InvalidKeyException e){
			e.printStackTrace();
		} catch (UnsupportedEncodingException e){
			e.printStackTrace();
		} catch (SignatureException e){
			e.printStackTrace();
		}
    	
    	return null;
    }
    
    /**
     * SHA256WithRSA 验签
     * @param content
     * @param sign
     * @param publicKey
     * @param charset
     * @return
     */
    public static boolean rsa256CheckContent(String content, String sign, String publicKey,String charset){
    	try{
	    	KeyFactory keyFactory = KeyFactory.getInstance("RSA");
	    	byte[] encodedKey = Base64.getDecoder().decode(publicKey);
	    	PublicKey pubkey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
	    	
	    	Signature signature = Signature.getInstance("SHA256WithRSA");
	    	signature.initVerify(pubkey);
	    	
	    	if(charset != null && !"".equals(charset)){
	    		signature.update(content.getBytes(charset));
	    	}else{
	    		signature.update(content.getBytes());
	    	}
	    	return signature.verify(Base64.getDecoder().decode(sign.getBytes()));
    	} catch (NoSuchAlgorithmException e){
    		e.printStackTrace();
    	} catch (InvalidKeySpecException e){
    		e.printStackTrace();
    	} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (SignatureException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
    	return false;
    }
    
   
    /**
     * 私钥加密方法（非对称）
     *@param parameterStr 明文字符串
     *@param aliasName 证书别名
     *@param keystorePwd 证书密码
     *@param inputCharset 字符集
     *@param privateFilePath 私钥证书路径
     *@return
     * @author ex_liukai
     * @see
     */
    public static String axaSign(String parameterStr,String aliasName,
        String keystorePwd,String inputCharset,String privateFilePath){
      String base64 = "";
      try{
        KeyStore ks = KeyStore.getInstance("PKCS12");
        //私钥证书地址
        FileInputStream ksfis = new FileInputStream(privateFilePath);
        BufferedInputStream ksbufin = new BufferedInputStream(ksfis);
        //私钥密码
        char[] keyPwd = keystorePwd.toCharArray();
        ks.load(ksbufin, keyPwd);

        PrivateKey priK = (PrivateKey)ks.getKey("test-alias", keyPwd);
        Signature signature = Signature.getInstance("SHA1withRSA");
        signature.initSign(priK);
        signature.update(parameterStr.getBytes(inputCharset));
        BASE64Encoder encoder = new BASE64Encoder();
        base64 = encoder.encode(signature.sign());
      }catch (FileNotFoundException e) {
    	  e.printStackTrace();
        logger.error(e);
      } catch (Exception ex) {
    	  ex.printStackTrace();
        logger.error(ex);
      }

      return base64;
    }
    /**
     * 解密方法
     *@param parameterStr 明文字符串
     *@param sign 加密串
     *@param publicFilePath 公钥证书路径
     *@return
     * @author ex_liukai
     * @see
     */
    public static boolean axaEnCodeByCer(String parameterStr, String sign,String publicFilePath){
      boolean flag = false;
      try{
        //公钥证书文件
        InputStream inStream = new FileInputStream(publicFilePath);
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        X509Certificate cert = (X509Certificate)cf.generateCertificate(inStream);
        PublicKey pk = cert.getPublicKey();
        Signature signature = Signature.getInstance("SHA1withRSA");
        signature.initVerify(pk);
        signature.update(parameterStr.getBytes());
        BASE64Decoder decoder = new BASE64Decoder();
        flag = signature.verify(decoder.decodeBuffer(sign));
      } catch (Exception e) {
        System.out.println(e.toString());
      }
      return flag;
    }
    
    

   /**
     * 返回 MessageDigest MD5
     */
   private static MessageDigest getDigest() {
	   try {
           return MessageDigest.getInstance("MD5");
       } catch (NoSuchAlgorithmException e) {
           throw new RuntimeException(e);
       }
	}

	/**
    * 返回 MessageDigest MD5
    */
	private static MessageDigest getDigestBySha() {
		try {
			return MessageDigest.getInstance("SHA-256");
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);
		}
	}
	private static MessageDigest getDigestBySha1() {
		try {
			return MessageDigest.getInstance("SHA-1");
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);
		}
	}
    /**
     * MD5加密，并返回作为一个十六进制字节
     */
    public static byte[] md5(byte[] data) {
        return getDigest().digest(data);
    }

    /**
     * SHA-256加密，并返回作为一个十六进制字节
     */
    public static byte[] sha256(byte[] data) {
        return getDigestBySha().digest(data);
    }
    public static byte[] sha1(byte[] data) {
        return getDigestBySha1().digest(data);
    }
    /**
     * MD5加密，并返回作为一个十六进制字节
     * <code>byte[]</code>.
     * @param data  Data to digest
     * @return MD5 digest
     */
    public static byte[] md5(String data,String charSet) {
    	if(CommonUtil.isNullOrBlank(charSet)){
    		charSet = "UTF-8";
    	}
    	byte[] bytes = null;
        try {
        	bytes = md5(data.getBytes(charSet));
		} catch (UnsupportedEncodingException e) {
			logger.error("MD5加密出错。",e);
		}
		return bytes;
    }

    /**
     * MD5加密，并返回一个32字符的十六进制值
     */
    public static String md5Hex(byte[] data) {
        return toHexString(md5(data));
    }

    /**
     * MD5加密，并返回一个32字符的十六进制值
     */
    public static String md5Hex(String data,String charSet) {
        return toHexString(md5(data,charSet));
    }
    /**
     * SHA256加密
     */
    public static String sha256Hex(String data,String charSet) {
    	if(CommonUtil.isNullOrBlank(charSet)){
    		charSet = "UTF-8";
    	}

        try {
			return toHexString(sha256(data.getBytes(charSet)));
		} catch (UnsupportedEncodingException e) {
			logger.error("MD5加密出错。",e);
			return null;
		}
    }
    
    public static String sha1Hex(String data,String charSet) {
    	if(CommonUtil.isNullOrBlank(charSet)){
    		charSet = "UTF-8";
    	}

        try {
			return toHexString(sha1(data.getBytes(charSet)));
		} catch (UnsupportedEncodingException e) {
			logger.error("MD5加密出错。",e);
			return null;
		}
    }
    
    private static String toHexString(byte[] b) {
        StringBuffer stringbuffer = new StringBuffer();
        for (int i = 0; i < b.length; i++) {
        	stringbuffer.append(HEX_CHARS.charAt(b[i] >>> 4 & 0x0F));
        	stringbuffer.append(HEX_CHARS.charAt(b[i] & 0x0F));
        }
        return stringbuffer.toString();
    }
}
