WeChatDecryptUtils.java 5.1 KB
Newer Older
苗卫卫 committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
package com.boco.nbd.wios.wx.utils;

import com.boco.nbd.cams.core.constant.CamsConstant;
import com.ihidea.component.pay.ail.Base64;
import com.ihidea.core.util.JSONUtilsEx;
import com.ihidea.core.util.StringUtilsEx;
import org.apache.commons.lang.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.AlgorithmParameters;
import java.security.Security;
import java.util.Arrays;
import java.util.Map;

/**
 * 微信解密工具类
 *
 * @author lvpeng
 * @version [版本号]
 * @date  2017年11月6日
 */
public class WeChatDecryptUtils {

	private static final Logger logger = LoggerFactory.getLogger(WeChatDecryptUtils.class);

	 public static Map<String, Object> decode(String sessionKey, String encryptedData, String iv) {

	        //转义字符处理
	        encryptedData = StringUtilsEx.unescapeXss(encryptedData);
	        iv = StringUtilsEx.unescapeXss(iv);
	        sessionKey = StringUtilsEx.unescapeXss(sessionKey);
	        byte[] decrypted = decrypt(sessionKey, encryptedData, iv);
	        if (null != decrypted && decrypted.length > 0) {
	            String jsonStr = new String(decodeForWxPKCS7(decrypted));
	            if (StringUtils.isNotBlank(jsonStr)) {
	                return JSONUtilsEx.deserialize(jsonStr, Map.class);
	            }
	        }
	        return null;
	    }


	 /**
	     * AES解密
	     *
	     * @author lvpeng
	     * @date 2017年9月7日
	     * @param sessionKey    密钥
	     * @param encryptedData 加密内容
	     * @param iv 加密算法的偏移量
	     * @return
	     */
	    public static byte[] decrypt(String sessionKey, String encryptedData, String iv) {
//	    	  logger.error("sessionKey:{},encryptedData:{},iv:{}", new String[]{sessionKey, encryptedData, iv});
	        byte[] aesKey = Base64.decode(sessionKey);
	        byte[] aesData = Base64.decode(encryptedData);
	        byte[] aesIv = Base64.decode(iv);
	        Security.addProvider(new BouncyCastleProvider());
	        try {
	            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
	            SecretKeySpec keyspec = new SecretKeySpec(aesKey, "AES");
	            IvParameterSpec ivspec = new IvParameterSpec(aesIv);
	            cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
	            byte[] original = cipher.doFinal(aesData);
	            return original;
	        } catch (Exception e) {
	            logger.error("解密失败");
	            return null;
	        }
	    }

	    /**
	     * 删除解密后明文的补位字符
	     *
	     * @param decrypted 解密后的明文
	     * @return 删除补位字符后的明文
	     */
	    private static byte[] decodeForWxPKCS7(byte[] decrypted) {
	        int pad = decrypted[decrypted.length - 1];
	        if (pad < 1 || pad > 32) {
	            pad = 0;
	        }
	        return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
	    }

	    /**
	     * 解密微信用户数据
	     * @param sessionkey
	     * @param encryptedData
	     * @param iv
	     * @return
	     */
	    @SuppressWarnings("unchecked")
		public static String decryptWxUser(String sessionkey, String encryptedData, String iv) {
	    	if(StringUtils.isEmpty(sessionkey) || StringUtils.isEmpty(encryptedData) || StringUtils.isEmpty(iv)){
	    		return null;
	    	}
	        // 被加密的数据
	        byte[] dataByte = Base64.decode(encryptedData);
	        // 加密秘钥
	        byte[] keyByte = Base64.decode(sessionkey);
	        // 偏移量
	        byte[] ivByte = Base64.decode(iv);
	        try {
	               // 如果密钥不足16位,那么就补足.  这个if 中的内容很重要
	            int base = 16;
	            if (keyByte.length % base != 0) {
	                int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
	                byte[] temp = new byte[groups * base];
	                Arrays.fill(temp, (byte) 0);
	                System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
	                keyByte = temp;
	            }
	            // 初始化
	            Security.addProvider(new BouncyCastleProvider());
	            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding","BC");
	            SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
	            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
	            parameters.init(new IvParameterSpec(ivByte));
	            cipher.init(Cipher.DECRYPT_MODE, spec, parameters);
	            byte[] resultByte = cipher.doFinal(dataByte);
	            if (null != resultByte && resultByte.length > 0) {
	                String result = new String(resultByte, StandardCharsets.UTF_8);
	                Map<String, String> resultMap = JSONUtilsEx.deserialize(result, Map.class);
	                return resultMap!=null && resultMap.get("purePhoneNumber")!=null? resultMap.get("purePhoneNumber") : null;
	            }
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	        return null;
	    }
}