微信小程序对敏感数据加解密算法(Java)

这篇具有很好参考价值的文章主要介绍了微信小程序对敏感数据加解密算法(Java)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.背景介绍

微信小程序对敏感数据加解密算法,以获取微信的群ID(opengid)为例
微信端通过转发获取加密数据
微信端通过获取微信群聊场景下的小程序启动信息

获取的相关参数
微信小程序对敏感数据加解密算法(Java)
但官方提供的加密数据加解密算法所支持的语言却不包括Java
微信小程序对敏感数据加解密算法(Java)

接口如果涉及敏感数据(如wx.getUserInfo当中的 openId 和
unionId),接口的明文内容将不包含这些敏感数据。开发者如需要获取敏感数据,需要对接口返回的加密数据(encryptedData)
进行对称解密。 解密算法如下:

对称解密使用的算法为 AES-128-CBC,数据采用PKCS#7填充。 对称解密的目标密文为
Base64_Decode(encryptedData)。 对称解密秘钥 aeskey =
Base64_Decode(session_key), aeskey 是16字节。 对称解密算法初始向量
为Base64_Decode(iv),其中 iv 由数据接口返回。
微信官方提供了多种编程语言的示例代码((点击下载)。每种语言类型的接口名字均一致。调用方式可以参照示例。

另外,为了应用能校验数据的有效性,会在敏感数据加上数据水印( watermark )。

2.解决方案①

Entity类

@ApiModel(value = "OpenGIdDTO", description = "获取openGId的解密参数")
public class OpenGIdDTO {
    @ApiModelProperty(value = "需要加密的数据")
    private String encrypt;

    @ApiModelProperty(value = "对称加密秘钥")
    private String sessionKey;

    @ApiModelProperty(value = "对称加密算法初始向量")
    private String iv;

    public String getEncrypt() {
        return encrypt;
    }

    public void setEncrypt(String encrypt) {
        this.encrypt = encrypt;
    }

    public String getSessionKey() {
        return sessionKey;
    }

    public void setSessionKey(String sessionKey) {
        this.sessionKey = sessionKey;
    }

    public String getIv() {
        return iv;
    }

    public void setIv(String iv) {
        this.iv = iv;
    }
}

Controller层

    @ApiOperation(value = "获取openGId")
    @PostMapping(value = "/getOpenGId")
    public JSONObject getOpenId(@RequestBody OpenGIdDTO openGIdDTO) throws Exception {
        String decrypt = WXCore.decrypt(APPID, openGIdDTO.getEncrypt(), openGIdDTO.getSessionKey(), openGIdDTO.getIv());
        JSONObject json = JSON.parseObject(decrypt);
        return json;
    }

工具类

public class WXCore {

    private static final String WATERMARK = "watermark";
    private static final String APPID = "openGId";
    /**
     * 解密数据
     * @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.parseObject(result);
                String decryptAppid = jsonObject.getJSONObject(WATERMARK).getString("appid");
                if(!appId.equals(decryptAppid)){
                    result = "";
                }
            }
        } catch (Exception e) {
            result = "";
            e.printStackTrace();
        }
        return result;
    }
}
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;
    }
}

3.解决方案②

Entity类一致

Controller层

    @ApiOperation(value = "解密返参信息")
    @PostMapping(value = "/getMess")
    @UserAnnotation()
    public JSONObject getMess(@RequestBody OpenGIdDTO openGIdDTO) throws Exception {
        String decrypt = WxCryptUtils.decrypt(openGIdDTO.getEncrypt(), openGIdDTO.getIv(), openGIdDTO.getSessionKey());
        JSONObject json = JSON.parseObject(decrypt);
        return json;
    }

工具类

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 = data.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 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;
    }
}
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();
    }
}

4.实际使用中出现’javax.crypto.BadPaddingException: pad block corrupted’报错

出现原因:前端在调用取用户手机号的回调函数中,又调用了一遍login()方法,然后把加密数据传给我们来解密,在回调中不应该调用登陆的方法,这样会导致刷新sessionkey,当我们用之前保存的sessionkey时,可能导致sessionkey过期。用旧的sessionkey解密显sessionkey加密的数据,当然会报错。
解决方案:前端不要调用2次login()方法文章来源地址https://www.toymoban.com/news/detail-493499.html

到了这里,关于微信小程序对敏感数据加解密算法(Java)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java获取微信小程序code获取openid、session_key、unionid,获取授权信息解密获取手机号

    WechatUtils (具体实体类自己根据自己的业务需求配置就行) service impl实现类 👆这个代码已经可以解析出code信息,具体的业务流程自己去添加就ok 还是我们之前的WechatUtils,在里面添加getPhone方法 service impl实现类 👆以上就是本次的笔记了,大家有需要用的自取,有用记得点个赞

    2024年02月16日
    浏览(49)
  • 微信小程序逆向解密

    WeChatAppEx.exe 版本:2.0.6609.4 以融智云考学生端为例。 网上已经有关于微信小程序解密的非常优秀的文章,本着学习的目的便不参考相关内容。 笔者水平实在有限,如发现纰漏,还请读者不吝赐教。 工具:火绒剑 首先看看打开一个小程序微信做了点什么,对微信进行火绒行为

    2024年02月11日
    浏览(49)
  • 微信小程序--解密用户信息

    前端传值:encryptedData、iv、code step1:将code发送给微信服务器,获取openid和session_key step2:根据encryptedData、iv、session_key(会话密钥),通过AES解密获取到用户所有信息

    2024年02月15日
    浏览(39)
  • 微信小程序背景图片设置

    问题  :微信小程序通过css:background-image引入背景图片失败 [渲染层网络层错误] pages/wode/wode.wxss 中的本地资源图片无法通过 WXSS 获取,可以使用网络图片,或者 base64,或者使用image/标签 解决方法微信小程序在使用background-image设置背景图时报错:渲染层网络层错误_index.wxss 中的

    2024年02月04日
    浏览(60)
  • 微信小程序 背景图片设置

            微信小程序设置背景图片时,有两种方法:         第一:直接在.wxss中中使用 “background-image:url()” 设置背景图片,但是这种加载背景图片的方法存在一个问题,就是所加载的图片只能是 网络图片 或 base64 图片,是不可以加载本地图片的。 但是使用base64图片

    2024年02月11日
    浏览(66)
  • 微信小程序前端加解密逆向分析

    某小程序渗透测试项目,测试时发现请求包内容进行了加密 小程序文件目录: 使用网易Mumu模拟器,开启root权限,安装手机微信并访问指定小程序,然后打开RE文件管理器,在 data/data/com.tencent.mm/MicroMsg 会生成一个md5加密命名的文件夹,在该文件夹下的 appbrand/pkg 目录下找到

    2024年02月05日
    浏览(56)
  • uniapp微信小程序设置背景渐变

    最近有个项目要用到背景渐变,背景渐变主要用到css,代码如下: 实现原理,position:fixed 固定定位、background-image: linear-gradient 线性渐变和 z-index 设置元素的堆叠顺序。

    2024年02月11日
    浏览(43)
  • 微信小程序之 base-64加密、解密

    后端获取 token 接口,需要加密认证

    2024年02月11日
    浏览(63)
  • 微信小程序~如何设置页面的背景色

    众所周知,微信小程序每个页面由.json,.scss,.ts,.wxml这四个文件组成。 有的小伙伴会发现,需要给页面加背景色的时候,只需在此页面的.scss文件中写个page{background-color: #f8f8f8;}就能生效,却不知其所以然。 这是因为 微信小程序的每个页面,都有一个page根标签 ,见“调试

    2024年04月10日
    浏览(50)
  • js 微信小程序aes解密-CryptoJS

    随着微信小程序的不断发展,js这门技术也越来越重要,很多人都开启了学习js,本文就介绍了aes解密。 crypto-js 是一个纯 javascript 写的加密算法类库 ,可以非常方便地在 javascript 进行 MD5、SHA1、SHA2、SHA3、RIPEMD-160 哈希散列,进行 AES、DES、Rabbit、RC4、Triple DES 加解密。 我们可

    2024年02月16日
    浏览(57)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包