package cn.qg.qaplatform.stools.utils.kdsp;

import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;

/**
 * kdsp
 * RSA非对称加密工具类
 */
public class RSA {
    /** 指定key的大小 */
    private static int KEYSIZE = 1024;

    /**
     * 生成密钥对
     */
    public static Map<String, String> generateKeyPair() throws Exception {
        /** RSA算法要求有一个可信任的随机数源 */
        SecureRandom sr = new SecureRandom();
        /** 为RSA算法创建一个KeyPairGenerator对象 */
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        /** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */
        kpg.initialize(KEYSIZE, sr);
        /** 生成密匙对 */
        KeyPair kp = kpg.generateKeyPair();
        /** 得到公钥 */
        Key publicKey = kp.getPublic();
        byte[] publicKeyBytes = publicKey.getEncoded();
        String pub = new String(Base64.getEncoder().encode(publicKeyBytes), ConfigureEncryptAndDecrypt.CHAR_ENCODING);
        /** 得到私钥 */
        Key privateKey = kp.getPrivate();
        byte[] privateKeyBytes = privateKey.getEncoded();
        String pri = new String(Base64.getEncoder().encode(privateKeyBytes), ConfigureEncryptAndDecrypt.CHAR_ENCODING);

        Map<String, String> map = new HashMap<String, String>();
        map.put("publicKey", pub);
        map.put("privateKey", pri);
        return map;
    }

    /**
     * 使用私钥生成签名
     * @param content
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static String sign(String content, String privateKey) throws Exception {
        PrivateKey priKey = getPrivateKey(privateKey);
        Signature signature = Signature.getInstance("SHA1WithRSA");
        signature.initSign(priKey);
        signature.update(content.getBytes(ConfigureEncryptAndDecrypt.CHAR_ENCODING));

        byte[] signed = signature.sign();
        return new String(Base64.getEncoder().encode(signed), ConfigureEncryptAndDecrypt.CHAR_ENCODING);
    }

    /**
     * 使用公钥验证签名
     * @param content
     * @param sign 签名
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static boolean checkSign(String content, String sign, String publicKey) throws Exception {
        PublicKey pubKey = getPublicKey(publicKey);
        Signature signature = Signature.getInstance("SHA1WithRSA");

        signature.initVerify(pubKey);
        signature.update(content.getBytes(ConfigureEncryptAndDecrypt.CHAR_ENCODING));

        return signature.verify(Base64.getDecoder().decode(sign));
    }

    /**
     * 加密方法
     * @param source 明文
     * @param publicKey 公钥
     * @return
     * @throws Exception
     */
    public static String encryptToBase64(String source, String publicKey) throws Exception {
        Key key = getPublicKey(publicKey);
        /** 得到Cipher对象来实现对源数据的RSA加密 */
        Cipher cipher = Cipher.getInstance(ConfigureEncryptAndDecrypt.RSA_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] b = source.getBytes(ConfigureEncryptAndDecrypt.CHAR_ENCODING);
        /** 执行加密操作 */
        byte[] b1 = cipher.doFinal(b);
        return new String(Base64.getEncoder().encode(b1), ConfigureEncryptAndDecrypt.CHAR_ENCODING);
    }

    /**
     * 解密算法
     * @param cryptograph 密文
     * @param privateKey 私钥
     * @return
     * @throws Exception
     */
    public static String decryptFromBase64(String cryptograph, String privateKey) throws Exception {
        Key key = getPrivateKey(privateKey);
        /** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
        Cipher cipher = Cipher.getInstance(ConfigureEncryptAndDecrypt.RSA_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] b1 = Base64.getDecoder().decode(cryptograph.getBytes());
        /** 执行解密操作 */
        byte[] b = cipher.doFinal(b1);
        return new String(b);
    }

    /**
     * 得到私钥
     * @param key 密钥字符串（经过base64编码）
     * @throws Exception
     */
    private static PrivateKey getPrivateKey(String key) throws Exception {
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(
                Base64.getDecoder().decode(key.getBytes(ConfigureEncryptAndDecrypt.CHAR_ENCODING)));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return privateKey;
    }

    /**
     * 得到公钥
     * @param key 密钥字符串（经过base64编码）
     * @throws Exception
     */
    private static PublicKey getPublicKey(String key) throws Exception {
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(
                Base64.getDecoder().decode(key.getBytes(ConfigureEncryptAndDecrypt.CHAR_ENCODING)));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }

    public static void main(String[] args) throws Exception {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(KEYSIZE);
        KeyPair kp = kpg.generateKeyPair();
        String privateKey = new String(Base64.getEncoder().encode(kp.getPrivate().getEncoded()));
        String publicKey = new String(Base64.getEncoder().encode(kp.getPublic().getEncoded()));
        System.out.println(privateKey);
        System.out.println(publicKey);
    }

}
