package cn.common.common.utils.wx;


import cn.hutool.core.codec.Base64;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.security.Key;
import java.security.Security;

/**
 * @author Singer create by Singer email:singer-coder@qq.com
 * @packageName cn.common.common.utils
 * @Description: 微信解密工具类,用于解密微信敏感信息
 * @date 2021-01-30
 */
@Slf4j
public class WxDecryptUtils {

    /**
     * 解密算法:AES
     */
    private static final String AES ="AES";

    /**
     * AES_CBC_PKCS7
     */
    private static final String AES_CBC_PKCS7 ="AES/CBC/PKCS5Padding";

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * <p>对小程序wx.getUserInfo 返回的数据进行解密</p>
     * <br>开发者如需要拿到敏感数据，需要对接口返回的加密数据( encryptedData )进行对称解密。 解密算法如下：</br>
     * <li>对称解密使用的算法为 AES-128-CBC，数据采用PKCS#7填充</li>
     * <li>对称解密的目标密文为 Base64_Decode(encryptedData)</li>
     * <li>对称解密秘钥 aeskey = Base64_Decode(session_key), aeskey 是16字节。</li>
     * <li>对称解密算法初始向量 为Base64_Decode(iv)，其中iv由数据接口返回</li>
     * @param encryptedData		小程序wx.getUserInfo接口返回的密文
     * @param sessionKey		会话key
     * @param iv				小程序接口返回的初始向量
     * @return {"openId":"oJ1P50LFpYwzZYaPhV1bjOrM2etY","nickName":"dimi","gender":1,"language":"zh_CN","city":"Haidian","province":"Beijing","country":"CN","avatarUrl":"http://wx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTJjUAIicI0k90UNwz7tTyWt46HrMMaxgSFPcR7Zh0MKZ4vzKibht4Sy3SrTwmYWoFSFOZOE0O1QJ0GQ/0","unionId":"orZ7js0oYCV859piu1kybaWlKGVc","watermark":{"timestamp":1493360456,"appid":"wxe87de3069cac4cf9"}}
     */

    public static String decrypt(String encryptedData,String iv,String sessionKey) {
        try {

            byte[] data = Base64.decode(encryptedData);

            byte[] aseKey = Base64.decode(sessionKey);

            byte[] ivData = Base64.decode(iv);

            Cipher cipher = Cipher.getInstance(AES_CBC_PKCS7);

            Key sKeySpec = new SecretKeySpec(aseKey, AES);
            // 初始化
            cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIv(ivData));

            byte[] result = cipher.doFinal(data);

            return new String(result);

        } catch (Exception e) {
            log.error("微信小程序用户信息解密失败 ：{} ",e);
            return null;
        }

    }

    /**
     * 生成偏移量
     * @author: create by singer - Singer email:singer-coder@qq.com
     * @date 2021/3/30
     * @param iv 偏移量
     * @return AlgorithmParameters
     */
    public static AlgorithmParameters generateIv(byte[] iv) throws Exception{
        AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
        params.init(new IvParameterSpec(iv));
        return params;
    }

    public static void main(String[] args){

    }

}
