收藏
回答

微信公众号 消息加解密说明 使用官方sdk报错?

String decrypt(String text) {
    byte[] original;
    try {
        // 设置解密模式为AES的CBC模式
        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
        SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES");
        IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
        cipher.init(Cipher.DECRYPT_MODE, key_spec, iv);
        // 使用BASE64对密文进行解码
        byte[] encrypted = Base64.decodeBase64(text);
        // 解密
        original = cipher.doFinal(encrypted);
    } catch (Exception e) {
        e.printStackTrace();
        throw new AesException(AesException.DecryptAESError);
    }
    String xmlContent, from_id;
    try {
        // 去除补位字符
        byte[] bytes = PKCS7Encoder.decode(original);
        // 分离16位随机字符串,网络字节序和AppId
        byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);
        int xmlLength = recoverNetworkBytesOrder(networkOrder);
        System.out.println("xmlLength = " + xmlLength);
        xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
        from_id = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length),
            CHARSET);
    } catch (Exception e) {
        e.printStackTrace();
        throw new AesException(AesException.IllegalBuffer);
    }

    // appid不相同的情况
    if (StringUtils.isBlank(appid) && !from_id.equals(receiveid)) {
        throw new AesException(AesException.ValidateAppidError);
    }
    return xmlContent;
}

说明:企业微信消息回调解密正常,xmlLength 二三百;公众号消息解密时,xmlLength 是一个正负十位整数。创建URL时,企业微信需要解密echostr并返回解密后的字符串,而微信公众号直接返回无需解密,是否不是一个解密体系?为什么企业微信公众平台——公众号的上文档中的解密SDK,企业微信消息可以使用,公众号却使用不了,企业项目比较急!急需要解决!


日志:

2022-03-15 11:07:56.762  INFO 11212 --- [nio-8001-exec-1] c.g.wx.cp.controller.WXKeFuController    : 接收到回调:keFuId 1001, msg_signature e6e1869e1f94cf73f140ba0c96719956eddaf762, timestamp 1647313676, nonce 699393265
sPostData = <xml>
    <ToUserName><![CDATA[gh_251e2d32914a]]></ToUserName>
    <Encrypt><![CDATA[DF8rpixK6xQaLGPCM2QECCmQ1aNVCeDDr4ByF1r4ZoINJWpYwtBp8KMHCplPFTvf3Cv/wKjsCEDUxoZQpQyntIZIExeEr7glp4N+4+v+wCkWd0Kodm2cBkXPV6wXwW8aaiwWAIkqPKMU+ki5u+xqySVHAwhUg4KnQOw5XGhbrGC5JDCCPd6XtHT48aQ0xFdkzHoeVgyDDnqp4e4d4zPDVx6UIyTOh3tXd6NvAHIOEG1Gn2g8trZvrs88bBCXjtS2tY/1+ETGTZI7Bj+iu2m/l/eGyvQmEMAJlV6D2GZL/uPFXvrzdm2ThSZfz5epPcjWu6NbxyyFrT0UKMHkEmNccWxvGiasLG7/T6gGiqJzyhQN48NcN33Q2wp9q6WUARkUacC3sFNwI1dPQsaXjmmXgO/hDJrJVotkSv1D5sP+J0c=]]></Encrypt>
</xml>
encrypt = DF8rpixK6xQaLGPCM2QECCmQ1aNVCeDDr4ByF1r4ZoINJWpYwtBp8KMHCplPFTvf3Cv/wKjsCEDUxoZQpQyntIZIExeEr7glp4N+4+v+wCkWd0Kodm2cBkXPV6wXwW8aaiwWAIkqPKMU+ki5u+xqySVHAwhUg4KnQOw5XGhbrGC5JDCCPd6XtHT48aQ0xFdkzHoeVgyDDnqp4e4d4zPDVx6UIyTOh3tXd6NvAHIOEG1Gn2g8trZvrs88bBCXjtS2tY/1+ETGTZI7Bj+iu2m/l/eGyvQmEMAJlV6D2GZL/uPFXvrzdm2ThSZfz5epPcjWu6NbxyyFrT0UKMHkEmNccWxvGiasLG7/T6gGiqJzyhQN48NcN33Q2wp9q6WUARkUacC3sFNwI1dPQsaXjmmXgO/hDJrJVotkSv1D5sP+J0c=
appid = wxde9c540c3328dbcc
第三方收到URL中的签名:e6e1869e1f94cf73f140ba0c96719956eddaf762
第三方校验签名:e6e1869e1f94cf73f140ba0c96719956eddaf762
xmlLength = -566866243
java.lang.IllegalArgumentException: 20 > -566866223
	at java.util.Arrays.copyOfRange(Arrays.java:3519)
	at com.gyhn.wx.cp.model.qywx.WXBizMsgCrypt.decrypt(WXBizMsgCrypt.java:281)
	at com.gyhn.wx.cp.model.qywx.WXBizMsgCrypt.decryptMsg(WXBizMsgCrypt.java:365)
...........................
2022-03-15 11:07:56.799 ERROR 11212 --- [nio-8001-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is com.gyhn.wx.cp.model.AesException: 解密后得到的buffer非法] with root cause
com.gyhn.wx.cp.model.AesException: 解密后得到的buffer非法
	at com.gyhn.wx.cp.model.qywx.WXBizMsgCrypt.decrypt(WXBizMsgCrypt.java:286) ~[classes/:na]
	at com.gyhn.wx.cp.model.qywx.WXBizMsgCrypt.decryptMsg(WXBizMsgCrypt.java:365) ~[classes/:na]
...........................

出错代码

int xmlLength = recoverNetworkBytesOrder(networkOrder);
xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
回答关注问题邀请回答
收藏

6 个回答

  • 大冬瓜
    大冬瓜
    2023-05-08

    老哥解决了没有

    2023-05-08
    有用
    回复
  • 李强
    李强
    2022-12-31
    int xmlLength = recoverNetworkBytesOrder(networkOrder);
    
    官方给提供的代码,这行妥妥的有bug吧?
    1、密文是企微通知的
    2、签名校验通过
    3、执行这行代码的时候,从日志里抓了个报错的参数。debug出来,计算出来居然有19亿的长度。
    4、copyOfRange 执行这个方法的时候里面new byte[19亿]
    
    copyOfRange 方法里,有判断 to 必须 大于 from,xmlLength 计算出来个19亿,这是稳稳的会报异常啊。显然不满足jdk方法copyOfRange里的 to 大于 from的条件
    


    2022-12-31
    有用
    回复 1
    • 李强
      李强
      2022-12-31
      网络字节序定义:收到的第一个字节被当作高位看待,这就要求发送端发送的第一个字节应当是高位。而在发送端发送数据时,发送的第一个字节是该数字在内存中起始地址对应的字节。可见多字节数值在发送前,在内存中数值应该以大端法存放。


        所以,网络协议指定了通讯字节序:大端。只有在多字节数据处理时才需要考虑字节序,运行在同一台计算机上的进程相互通信时,一般不用考虑字节序,异构计算机之间通讯,需要转换自己的字节序为网络字节。主机字节序是小端,所以才需要进行字节序转换。
      ————————————————
      版权声明:本文为CSDN博主「~青萍之末~」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
      原文链接:https://blog.csdn.net/daaikuaichuan/article/details/83061117
      2022-12-31
      回复
  • Arno-阿诺
    Arno-阿诺
    2022-10-19

    你好,解决了吗?有碰到替换jar也没有效果


    2022-10-19
    有用
    回复
  • 旭
    2022-05-10

    你好,解决了么,我也碰到了

    2022-05-10
    有用
    回复
  • 鸿翎
    鸿翎
    2022-04-10

    您好,我也遇到一样的问题,在做XML解析时候,报内存溢出!

    int xmlLength = this.recoverNetworkBytesOrder(networkOrder);
    xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
    from_appid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET);
    

    主要是xmlLength长度换算出来可能太长了,导致内存溢出了!

    2022-04-10
    有用
    回复
  • 公众号技术运营专员-livia
    公众号技术运营专员-livia
    2022-03-16

    你好,你可以提供一下你使用的相关API文档给我们查看吗

    2022-03-16
    有用
    回复
登录 后发表内容