原来Java是这样实现微信小程序加密与解密数据算法的!超赞的有木有?!

在线体验各类最新模型,更有模型 免费Token 额度领取!
立即体验
简介: 微信推出了小程序,很多公司的客户端应用不仅具有了APP、H5、还接入了小程序开发。但是,小程序中竟然没有提供Java版本的加密数据解密算法。这着实让广大的Java开发人员蛋疼。

一、概述


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


微信小程序提供的加密数据解密算法链接为:https://mp.weixin.qq.com/debug/wxadoc/dev/api/signature.html

最新的加密数据解密算法链接地址为:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/signature.html

我们下载的算法示例如下:


SS.jpg


木有Java! 木有Java! 木有Java!

那么如何解决这个问题,我们一起来实现Java版本的微信小程序加密数据解密算法。


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


1、创建项目


这里,我们创建一个Maven工程,具体创建步骤略。


2、配置pom.xml


我们在pom.xml中加入如下配置。

<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.4</version>
</dependency>
<dependency> 
    <groupId>net.sf.json-lib</groupId> 
    <artifactId>json-lib</artifactId> 
    <version>2.2.3</version> 
    <classifier>jdk15</classifier> 
</dependency>


3、实现AES类

package io.binghe.wechat.crypto.wx;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
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 org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
 * AES加密
 * @author binghe
 *
 */
public class AES {
  public static boolean initialized = false;
  /**
   * AES解密
   * 
   * @param content
   *            密文
   * @return
   * @throws InvalidAlgorithmParameterException
   * @throws NoSuchProviderException
   */
  public byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) throws InvalidAlgorithmParameterException {
    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;
  }
}


4、实现WxPKCS7Encoder类

package io.binghe.wechat.crypto.wx;
import java.nio.charset.Charset;
import java.util.Arrays;
/**
 * 微信小程序加解密
 * @author binghe
 *
 */
public class WxPKCS7Encoder {
  private static final Charset CHARSET = Charset.forName("utf-8");
  private static final int BLOCK_SIZE = 32;
  /**
   * 获得对明文进行补位填充的字节.
   *
   * @param count
   *            需要进行填充补位操作的明文字节个数
   * @return 补齐用的字节数组
   */
  public static byte[] encode(int count) {
    // 计算需要填充的位数
    int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
    if (amountToPad == 0) {
      amountToPad = BLOCK_SIZE;
    }
    // 获得补位所用的字符
    char padChr = chr(amountToPad);
    String tmp = new String();
    for (int index = 0; index < amountToPad; index++) {
      tmp += padChr;
    }
    return tmp.getBytes(CHARSET);
  }
  /**
   * 删除解密后明文的补位字符
   *
   * @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);
  }
  /**
   * 将数字转化成ASCII码对应的字符,用于对明文进行补码
   *
   * @param a
   *            需要转化的数字
   * @return 转化得到的字符
   */
  public static char chr(int a) {
    byte target = (byte) (a & 0xFF);
    return (char) target;
  }
}


5、实现WXCore类


这个类主要是对具体算法的封装,统一对外提供方法。


package io.binghe.wechat.crypto.wx;
import org.apache.commons.codec.binary.Base64;
import net.sf.json.JSONObject;
/**
 * 封装对外访问方法
 * @author binghe
 *
 */
public class WXCore {
  private static final String WATERMARK = "watermark";
  private static final String APPID = "appid";
  /**
   * 解密数据
   * @return
   * @throws Exception
   */
  public static String decrypt(String appId, String encryptedData, String sessionKey, String iv){
    String result = "";
    try {
      AES aes = new AES();  
        byte[] resultByte = aes.decrypt(Base64.decodeBase64(encryptedData), Base64.decodeBase64(sessionKey), Base64.decodeBase64(iv));  
        if(null != resultByte && resultByte.length > 0){  
            result = new String(WxPKCS7Encoder.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;
  }
  public static void main(String[] args) 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==";
       System.out.println(decrypt(appId, encryptedData, sessionKey, iv));
    }
}


三、测试


1、运行Java版微信小程序加密数据解密算法


这里我们就直接运行WXcore类的main方法,这里的测试数据都是从Python版微信小程序加密数据解密算法的示例程序中提出来的。我们的运行结果如下:


{"openId":"oGZUI0egBJY1zhBYw2KhdUfwVJJE","nickName":"Band","gender":1,"language":"zh_CN","city":"Guangzhou","province":"Guangdong","country":"CN","avatarUrl":"http://wx.qlogo.cn/mmopen/vi_32/aSKcBBPpibyKNicHNTMM0qJVh8Kjgiak2AHWr8MHM4WgMEm7GFhsf8OYrySdbvAMvTsw3mo8ibKicsnfN5pRjl1p8HQ/0","unionId":"ocMvos6NjeKLIBqg5Mr9QjxrP1FA","watermark":{"timestamp":1477314187,"appid":"wx4f4bc4dec97d474b"}


2、运行Python版微信小程序加密数据解密算法


这里我们在python环境中直接运行微信官方提供的Python版小程序加密数据解密算法,结果如下:



{u'province': u'Guangdong', u'openId': u'oGZUI0egBJY1zhBYw2KhdUfwVJJE', u'language': u'zh_CN', u'city': u'Guangzhou', u'gender': 1, u'avatarUrl': u'http://wx.qlogo.cn/mmopen/vi_32/aSKcBBPpibyKNicHNTMM0qJVh8Kjgiak2AHWr8MHM4WgMEm7GFhsf8OYrySdbvAMvTsw3mo8ibKicsnfN5pRjl1p8HQ/0', u'watermark': {u'timestamp': 1477314187, u'appid': u'wx4f4bc4dec97d474b'}, u'country': u'CN', u'nickName': u'Band', u'unionId': u'ocMvos6NjeKLIBqg5Mr9QjxrP1FA'}


通过对比以上结果可知,我们自行使用Java实现的Java版微信小程序加密数据解密算法与微信官方提供的Python版小程序加密数据解密算法结果一致。


相关文章
|
10月前
|
Java API 开发工具
【Azure Developer】Java代码实现获取Azure 资源的指标数据却报错 "invalid time interval input"
在使用 Java 调用虚拟机 API 获取指标数据时,因本地时区设置非 UTC,导致时间格式解析错误。解决方法是在代码中手动指定时区为 UTC,使用 `ZoneOffset.ofHours(0)` 并结合 `withOffsetSameInstant` 方法进行时区转换,从而避免因时区差异引发的时间格式问题。
421 4
|
10月前
|
算法 Java
Java多线程编程:实现线程间数据共享机制
以上就是Java中几种主要处理多线程序列化资源以及协调各自独立运行但需相互配合以完成任务threads 的技术手段与策略。正确应用上述技术将大大增强你程序稳定性与效率同时也降低bug出现率因此深刻理解每项技术背后理论至关重要.
609 16
|
11月前
|
数据采集 JSON Java
Java爬虫获取1688店铺所有商品接口数据实战指南
本文介绍如何使用Java爬虫技术高效获取1688店铺商品信息,涵盖环境搭建、API调用、签名生成及数据抓取全流程,并附完整代码示例,助力市场分析与选品决策。
|
11月前
|
数据采集 存储 前端开发
Java爬虫性能优化:多线程抓取JSP动态数据实践
Java爬虫性能优化:多线程抓取JSP动态数据实践
|
12月前
|
存储 搜索推荐 算法
加密算法、排序算法、字符串处理及搜索算法详解
本文涵盖四大类核心技术知识。加密算法部分介绍了对称加密(如 AES)、非对称加密(如 RSA)、哈希摘要(如 SHA-2)、签名算法的特点及密码存储方案(加盐、BCrypt 等)。 排序算法部分分类讲解了比较排序(冒泡、选择、插入、归并、快排、堆排序)和非比较排序(计数、桶、基数排序)的时间复杂度、适用场景及实现思路,强调混合排序的工业应用。 字符串处理部分包括字符串反转的双指针法,及项目中用正则进行表单校验、网页爬取、日志处理的实例。 搜索算法部分详解了二分查找的实现(双指针与中间索引计算)和回溯算法的概念(递归 + 剪枝),以 N 皇后问题为例说明回溯应用。内容全面覆盖算法原理与实践
332 0
|
算法 数据安全/隐私保护
基于混沌加密的遥感图像加密算法matlab仿真
本项目实现了一种基于混沌加密的遥感图像加密算法MATLAB仿真(测试版本:MATLAB2022A)。通过Logistic映射与Baker映射生成混沌序列,对遥感图像进行加密和解密处理。程序分析了加解密后图像的直方图、像素相关性、信息熵及解密图像质量等指标。结果显示,加密图像具有良好的随机性和安全性,能有效保护遥感图像中的敏感信息。该算法适用于军事、环境监测等领域,具备加密速度快、密钥空间大、安全性高的特点。
|
9月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
426 1
|
9月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
392 1
|
10月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案