Java实现微信小程序加密数据解密算法

Posted kuku_zhongzi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java实现微信小程序加密数据解密算法相关的知识,希望对你有一定的参考价值。

Java实现微信小程序加密数据解密算法

一.概述

微信推出了小程序,很多公司的客户端应用不仅具有了APP、H5、还接入了小程序开发。但是,小程序中竟然没有提供Java版本的加密数据解密算法。

微信小程序提供的加密数据解密算法链接为
https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/signature.html

二.实现Java版本的微信小程序加密数据解密算法

  • 1.配置pom.xml
    我们在pom.xml中加入如下配置,其中bcprov-jdk15on是为了支持AES的BouncyCastleProvider,而commons-codec则是为了顺利的对session_key,iv,encryptData进行Base64的编解码
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk16</artifactId>
    <version>1.46</version>
</dependency>
 
<dependency>
  	<groupId>commons-codec</groupId>
  	<artifactId>commons-codec</artifactId>
  	<version>1.10</version>
</dependency>
 
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.29</version>
</dependency>
  • 2.封装WxDecryptUtil 解密工具类
import net.sf.json.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.util.Arrays;

/**
 * 封装工具类
 * @author kuku_zhongzi
 */
 
public class WxDecryptUtil 

    public static boolean initialized = false;
    private static final String WATERMARK = "watermark";
    private static final String APPID = "appid";

    /**
     * 解密数据
     */
    public static String decrypt(String appId, String encryptedData, String sessionKey, String iv) 
        String result = "";
        try 
            byte[] resultByte = decrypt(Base64.decodeBase64(encryptedData), Base64.decodeBase64(sessionKey), Base64.decodeBase64(iv));
            if (null != resultByte && resultByte.length > 0) 
                result = new String(decode(resultByte));
                JSONObject jsonObject = JSONObject.fromObject(result);
                String decryptAppid = jsonObject.getJSONObject(WATERMARK).getString(APPID);
                if (!appId.equals(decryptAppid)) 
                    result = "";
                
            
         catch (Exception e) 
            result = "";
            e.printStackTrace();
        
        return result;
    

    /**
     * @param content 密文
     */
    public static byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) 
        initialize();
        try 
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            Key sKeySpec = new SecretKeySpec(keyByte, "AES");
            cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));// 初始化
            byte[] result = cipher.doFinal(content);
            return result;
         catch (NoSuchAlgorithmException e) 
            e.printStackTrace();
         catch (NoSuchPaddingException e) 
            e.printStackTrace();
         catch (InvalidKeyException e) 
            e.printStackTrace();
         catch (IllegalBlockSizeException e) 
            e.printStackTrace();
         catch (BadPaddingException e) 
            e.printStackTrace();
         catch (NoSuchProviderException e) 
            // TODO Auto-generated catch block
            e.printStackTrace();
         catch (Exception e) 
            // TODO Auto-generated catch block
            e.printStackTrace();
        
        return null;
    

    public static void initialize() 
        if (initialized)
            return;
        Security.addProvider(new BouncyCastleProvider());
        initialized = true;
    

    // 生成iv
    public static AlgorithmParameters generateIV(byte[] iv) throws Exception 
        AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
        params.init(new IvParameterSpec(iv));
        return params;
    

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

三.测试

以下数据都是测试数据 仅供学习参考

微信的js_code时效性只有一次,用过一次之后不能再用了,注意查看

js_code 用于获取openid、sessionKey、appId

@Test
public void test() throws Exception 
		String appId = "wx4f4bc4dec97d474b";
		String encryptedData = "CiyLU1Aw2KjvrjMdj8YKliAjtP4gsMZMQmRzooG2xrDcvSnxIMXFufNstNGTyaGS9uT5geRa0W4oTOb1WT7fJlAC+oNPdbB+3hVbJSRgv+4lGOETKUQz6OYStslQ142dNCuabNPGBzlooOmB231qMM85d2/fV6ChevvXvQP8Hkue1poOFtnEtpyxVLW1zAo6/1Xx1COxFvrc2d7UL/lmHInNlxuacJXwu0fjpXfz/YqYzBIBzD6WUfTIF9GRHpOn/Hz7saL8xz+W//FRAUid1OksQaQx4CMs8LOddcQhULW4ucetDf96JcR3g0gfRK4PC7E/r7Z6xNrXd2UIeorGj5Ef7b1pJAYB6Y5anaHqZ9J6nKEBvB4DnNLIVWSgARns/8wR2SiRS7MNACwTyrGvt9ts8p12PKFdlqYTopNHR1Vf7XjfhQlVsAJdNiKdYmYVoKlaRv85IfVunYzO0IKXsyl7JCUjCpoG20f0a04COwfneQAGGwd5oa+T8yO5hzuyDb/XcxxmK01EpqOyuxINew==";
		String sessionKey = "tiihtNczf5v6AKRyjwEUhQ==";
		String iv = "r7BXXKkLb8qrSNn05n0qiA==";
		JSONObject jsonObject = JSON.parseObject(WxDecryptUtil.decrypt(appId, encryptedData, sessionKey, iv));
		// jsonObject => "phoneNumber": "13580006666","purePhoneNumber": "13580006666","countryCode": "86","watermark":"appid":"APPID", "timestamp": 1618983
		System.out.println("用户绑定的手机号(国外手机号会有区号):" + jsonObject.getString("phoneNumber"));  //  13580006666
		System.out.println("不带区号的手机号:" + jsonObject.getString("purePhoneNumber"));  // 13580006666
		System.out.println("区号:" + jsonObject.getString("countryCode"));  // 86

亲测:运行结果和微信官网示例一致

附:

jar包下载地址:http://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk16/1.46

以上是关于Java实现微信小程序加密数据解密算法的主要内容,如果未能解决你的问题,请参考以下文章

Java实现微信小程序加密数据解密算法

微信小程序加密数据解密算法-Java实现

微信小程序加密数据解密算法-Java实现

微信小程序session_key解析中反斜杠问题处理 Java解析

微信小程序session_key解析中反斜杠问题处理 Java解析

微信小程序crypto-js AES 加解密数据