小程序加密数据解密算法java版

小程序开发者如需要获取敏感数据,需要对接口返回的加密数据( encryptedData )进行对称解密。 解密算法如下:

  1. 对称解密使用的算法为 AES-128-CBC,数据采用PKCS#7填充。
  2. 对称解密的目标密文为 Base64_Decode(encryptedData)。
  3. 对称解密秘钥 aeskey = Base64_Decode(session_key), aeskey 是16字节。
  4. 对称解密算法初始向量 为Base64_Decode(iv),其中iv由数据接口返回。

这里使用微信提供的 PKCS7Encoder 对小程序进行加密数据解密, 也提供了加密方法


import java.nio.charset.Charset;
import java.util.Arrays;

/**
 * 提供基于PKCS7算法的加解密接口.
 */
public class PKCS7Encoder {

    static Charset CHARSET = Charset.forName("utf-8");
    static 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 转化得到的字符
     */
    static char chr(int a) {
        byte target = (byte) (a & 0xFF);
        return (char) target;
    }

}
复制代码

import java.util.ArrayList;

public class ByteGroup {

    ArrayList<Byte> byteContainer = new ArrayList<Byte>();

    public byte[] toBytes() {
        byte[] bytes = new byte[byteContainer.size()];
        for (int i = 0; i < byteContainer.size(); i++) {
            bytes[i] = byteContainer.get(i);
        }
        return bytes;
    }

    public ByteGroup addBytes(byte[] bytes) {
        for (byte b : bytes) {
            byteContainer.add(b);
        }
        return this;
    }

    public int size() {
        return byteContainer.size();
    }
}
复制代码

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;


/**
 * @author yyb
 * @since 2018-01-10
 */
public class WxCryptUtils {

    /**
     * 小程序 数据解密
     *
     * @param encryptData 加密数据
     * @param iv          对称解密算法初始向量
     * @param sessionKey  对称解密秘钥
     * @return 解密数据
     */
    public static String decrypt(String encryptData, String iv, String sessionKey) throws Exception {
        AlgorithmParameters algorithmParameters = AlgorithmParameters.getInstance("AES");
        algorithmParameters.init(new IvParameterSpec(Base64.decodeBase64(iv)));
        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(Base64.decodeBase64(sessionKey), "AES"), algorithmParameters);
        byte[] decode = PKCS7Encoder.decode(cipher.doFinal(Base64.decodeBase64(encryptData)));
        String decryptStr = new String(decode, StandardCharsets.UTF_8);
        return decryptStr;
    }
    
    /**
     * 数据加密
     * 
     * @param data          需要加密的数据
     * @param iv            对称加密算法初始向量
     * @param sessionKey    对称加密秘钥
     * @return  加密数据
     */
    public static String encrypt(String data, String iv, String sessionKey) throws Exception {
        AlgorithmParameters algorithmParameters = AlgorithmParameters.getInstance("AES");
        algorithmParameters.init(new IvParameterSpec(Base64.decodeBase64(iv)));
        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(Base64.decodeBase64(sessionKey), "AES"), algorithmParameters);
        byte[] textBytes = json.getBytes(StandardCharsets.UTF_8);
        ByteGroup byteGroup= new ByteGroup();
        byteGroup.addBytes(textBytes);
        byte[] padBytes = PKCS7Encoder.encode(byteGroup.size());
        byteGroup.addBytes(padBytes);
        byte[] encryptBytes = cipher.doFinal(byteGroup.toBytes());
        return Base64.encodeBase64String(encryptBytes);
    }
    
    
    public static void main(String[] args) throws Exception {
        // 微信 小程序的 测试数据
        String encrypt = "CiyLU1Aw2KjvrjMdj8YKliAjtP4gsMZM\n" +
                "                QmRzooG2xrDcvSnxIMXFufNstNGTyaGS\n" +
                "                9uT5geRa0W4oTOb1WT7fJlAC+oNPdbB+\n" +
                "                3hVbJSRgv+4lGOETKUQz6OYStslQ142d\n" +
                "                NCuabNPGBzlooOmB231qMM85d2/fV6Ch\n" +
                "                evvXvQP8Hkue1poOFtnEtpyxVLW1zAo6\n" +
                "                /1Xx1COxFvrc2d7UL/lmHInNlxuacJXw\n" +
                "                u0fjpXfz/YqYzBIBzD6WUfTIF9GRHpOn\n" +
                "                /Hz7saL8xz+W//FRAUid1OksQaQx4CMs\n" +
                "                8LOddcQhULW4ucetDf96JcR3g0gfRK4P\n" +
                "                C7E/r7Z6xNrXd2UIeorGj5Ef7b1pJAYB\n" +
                "                6Y5anaHqZ9J6nKEBvB4DnNLIVWSgARns\n" +
                "                /8wR2SiRS7MNACwTyrGvt9ts8p12PKFd\n" +
                "                lqYTopNHR1Vf7XjfhQlVsAJdNiKdYmYV\n" +
                "                oKlaRv85IfVunYzO0IKXsyl7JCUjCpoG\n" +
                "                20f0a04COwfneQAGGwd5oa+T8yO5hzuy\n" +
                "                Db/XcxxmK01EpqOyuxINew==";

        String sessionKey = "tiihtNczf5v6AKRyjwEUhQ==";
        String iv = "r7BXXKkLb8qrSNn05n0qiA==";

        String decrypt = WxCryptUtils.decrypt(encrypt, iv, sessionKey);
        System.out.println(decrypt);
    }
}
复制代码

最后的结果:

{
  "country": "CN",
  "unionId": "ocMvos6NjeKLIBqg5Mr9QjxrP1FA",
  "gender": 1,
  "province": "Guangdong",
  "city": "Guangzhou",
  "avatarUrl": "http://wx.qlogo.cn/mmopen/vi_32/aSKcBBPpibyKNicHNTMM0qJVh8Kjgiak2AHWr8MHM4WgMEm7GFhsf8OYrySdbvAMvTsw3mo8ibKicsnfN5pRjl1p8HQ/0",
  "openId": "oGZUI0egBJY1zhBYw2KhdUfwVJJE",
  "nickName": "Band",
  "language": "zh_CN",
  "watermark": {
    "appid": "wx4f4bc4dec97d474b",
    "timestamp": 1477314187
  }
}
复制代码
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值