微信小程序中获取用户手机号密文数据解密报错问题

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

一、问题描述

微信小程序获取手机号,官方通常会返回密文数据给我们,此时就需要我们自行解密数据。在揭秘的数据过程中会发现,第一次授权获取手机号会出现错误,再次获取的时候就能够正常获取。
错误信息一般分两种:
密文后端解密的javax.crypto.BadPaddingException: pad block corrupted(后端语言为java)错误;
密文前端解密的
Illegal Buffer at WXBizDataCrypt.define.push.WXBizDataCrypt.decryptData
错误。

二、错误原因

在回调里面又调用一次wx.login()导致登录状态被刷新,此时用code换取的sessionKey,不是的当时encryptedData对应的sessionKey,这个时候就导致了解密失败。
例如:
微信小程序 解密手机号,微信小程序,小程序,前端

由于**@getphonenumber是获取用户手机号回调方法,然后又在回调中调用了一次login()**,导致出现上述问题。

三、解决方法

3.1 不推荐方法

当出现上述问题的时候,可以弹出提示,引导用户再点击一次授权,出现两次错误的几率还是不高的,业务允许的话,可以这么干。

3.2 正确方法

试想一下,出现问题的原因是啥,当然是在回调里面又重新login()了一下,那么能不能把login()放在回调外面。
也就是先调用
login()方法获取code(不要在@getphonenumbe里面调用login)
,然后在获取sessionKey,解密数据。
文章来源地址https://www.toymoban.com/news/detail-611727.html

四、附录

4.1 后端解密方法

import com.alibaba.fastjson.JSONObject;

WXBizDataCryptUtil util = new WXBizDataCryptUtil(properties.getAppId(), dto.getSessionKey());
JSONObject data = util.decrypt(dto.getEncryptedData(), dto.getIv());
import com.alibaba.fastjson.JSONObject;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.security.Key;
import java.security.Security;
import java.util.Base64;

/**
 * 微信数据解密工具
 *
 * @date 2023-06-08 16:51:26
 */
public class WXBizDataCryptUtil {

    public static JSONObject getMoreInfoFromEncryptedData(String appId, String sessionKey, String encryptedData, String iv) {
        WXBizDataCryptUtil pc = new WXBizDataCryptUtil(appId, sessionKey);
        JSONObject decrypt = pc.decrypt(encryptedData, iv);
        return decrypt;
    }

    private String appId;
    private String sessionKey;

    public WXBizDataCryptUtil(String appId, String sessionKey) {
        this.appId = appId;
        this.sessionKey = sessionKey;
    }

    /**
     * 解密成json
     *
     * @param encryptedData
     * @param iv
     * @return
     */
    public JSONObject decrypt(String encryptedData, String iv) {
        byte[] encryptedDataDecode = Base64.getDecoder().decode(encryptedData);
        byte[] sessionKeyDecode = Base64.getDecoder().decode(this.sessionKey);
        byte[] ivDecode = Base64.getDecoder().decode(iv);
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        byte[] decodeData = decode(encryptedDataDecode, sessionKeyDecode, ivDecode);
        String stringData = new String(decodeData);
        JSONObject jsonObject = JSONObject.parseObject(stringData);
        return jsonObject;
    }
    /**
     * 解密算法 AES-128-CBC
     * 填充模式 PKCS#7
     *
     * @param encryptedDataDecode 目标密文
     * @return
     * @throws Exception
     */
    private byte[] decode(byte[] encryptedDataDecode, byte[] sessionKeyDecode, byte[] iv) {
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            Key sKeySpec = new SecretKeySpec(sessionKeyDecode, "AES");
            cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIv(iv));// 初始化
            byte[] result = cipher.doFinal(encryptedDataDecode);
            return result;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 处理iv
     *
     * @param iv
     * @return
     * @throws Exception
     */
    private AlgorithmParameters generateIv(byte[] iv) throws Exception {
        AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
        params.init(new IvParameterSpec(iv));
        return params;
    }

}

4.2 前端解密

getPhoneNumber(e) {
  if (e.detail.errMsg === 'getPhoneNumber:ok') {
    getOpenId({
      code: this.wxCode
    })
      .then(openIdRes => {
        if (!openIdRes.success) {
          this.$refs.page.closeLoading()
          showErrorToast(this.$refs.uToast, {
            position: 'top',
            message: openIdRes.message
          })
          return
        }
        const data = openIdRes.data
        const wxCryto = new WXBizDataCrypt(data.appId, data.sessionKey)
        const encryptData = wxCryto.decryptData(e.detail.encryptedData, e.detail.iv)
        console.log('解密结果', encryptData)
      })
      .catch(err => {
        console.log(err)
        this.$refs.page.closeLoading()
        showErrorToast(this.$refs.uToast, {
          position: 'top',
          message: '获取微信参数异常, 请重试'
        })
      })
  }
}
var crypto = require('crypto')

function WXBizDataCrypt(appId, sessionKey) {
  this.appId = appId
  this.sessionKey = sessionKey
}

WXBizDataCrypt.prototype.decryptData = function (encryptedData, iv) {
  // base64 decode
  var sessionKey = new Buffer(this.sessionKey, 'base64')
  encryptedData = new Buffer(encryptedData, 'base64')
  iv = new Buffer(iv, 'base64')

  try {
     // 解密
    var decipher = crypto.createDecipheriv('aes-128-cbc', sessionKey, iv)
    // 设置自动 padding 为 true,删除填充补位
    decipher.setAutoPadding(true)
    var decoded = decipher.update(encryptedData, 'binary', 'utf8')
    decoded += decipher.final('utf8')
    
    decoded = JSON.parse(decoded)

  } catch (err) {
    throw new Error('Illegal Buffer')
  }

  if (decoded.watermark.appid !== this.appId) {
    throw new Error('Illegal Buffer')
  }

  return decoded
}

module.exports = WXBizDataCrypt

到了这里,关于微信小程序中获取用户手机号密文数据解密报错问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包