微信小程序解密encryptedData报错pad block corrupted

在这里插入图片描述前要: 今天调试一下微信授权登录的时候老是第一次报错解密失败pad block corrupted,第二次授权的时候正常,因为第一次已经获取到手机号码!

后端代码:

public static JSONObject getUserInfo(String encryptedData, String sessionKey, String iv) {
    
    
    try {
    
    
      // 加密秘钥
      byte[] keyByte = Base64.decodeBase64(sessionKey);
      // 偏移量
      byte[] ivByte = Base64.decodeBase64(iv);

      // 如果密钥不足16位,那么就补足.  这个if 中的内容很重要
      int base = 16;
      if (keyByte.length % base != 0) {
    
    
        int groups = keyByte.length / base + 1;
        byte[] temp = new byte[groups * base];
        Arrays.fill(temp, (byte) 0);
        System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
        keyByte = temp;
      }
      // 初始化
      Security.addProvider(new BouncyCastleProvider());
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
      SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
      AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
      parameters.init(new IvParameterSpec(ivByte));
      cipher.init(Cipher.DECRYPT_MODE, spec, parameters); // 初始化
      // 被加密的数据
      byte[] dataByte = Base64.decodeBase64(encryptedData);
      byte[] resultByte = cipher.doFinal(dataByte);
      if (null != resultByte && resultByte.length > 0) {
    
    
        String result = new String(resultByte, StandardCharsets.UTF_8);
        log.info("解析微信加密数据==>{}", result);
        return JSONObject.parseObject(result);
      }
    } catch (BadPaddingException e) {
    
    
      log.error("解析微信加密数据失败", e);
      throw Exceptions.fail(WECHAT_SESSION_EXPIRED);
    }
    return null;
  }

报错提示:

javax.crypto.BadPaddingException: pad block corrupted
	at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$BufferedGenericBlockCipher.doFinal(Unknown Source)
	at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(Unknown Source)
	at javax.crypto.Cipher.doFinal(Cipher.java:2088)
	at com.saic.ebiz.service.util.AESUtils.getUserInfo(AESUtils.java:62)
	at com.saic.ebiz.service.util.AESUtils.main(AESUtils.java:96)
Exception in thread "main" java.lang.NullPointerException
	at com.saic.ebiz.service.util.AESUtils.main(AESUtils.java:96)

查找了官方文档原来不是后端代码问题,而是前端代码问题~是微信的bug。不知道有没有解决,但我们自己可以去解决:就是执行顺序问题

原因: uni.login获取session_key,而sessionKey又是解密encryptedData的密钥,所以一旦我们的uni.login在uni.getUserInfo(getPhoneNumber)之后获取,我们存储的sessionKey绝对不是当前获取encryptedData的密钥。

  • 这是因为调用了uni.login后通过code获得的session_key是新的session_key.
  • 所以,在调用uni.login之前获的加密数据不是用新得session_key加密的数据。
  • 在调用uni.login之后获得的加密数据,才是新得的session_key加密的数据。

本来的执行顺序:

  1. 先触发getPhoneNumber获取了手机号的加密数据。
  2. 然后才调用的uni.login获取code。
  3. 再通过code取到用户的session_key 。
  4. 最后再用session_key,手机号的加密数据和向量解密获取手机号。

正确的做法应该是:

  1. 首先调用的uni.login获取code
  2. 再通过code取到用户session_key 。
  3. 再触发getPhoneNumber获取了手机号的加密数据
  4. 最后再用session_key,手机号的加密数据和向量解密获取手机号。

前端保证uni.login获取到的code在getUserInfo(getPhoneNumbe)操作之前。也可以是后端,因为项目是graphql,所以我是前端保证就行。社区还提供另外一种方案Cipher cipher = Cipher.getInstance(“AES/CBC/PKCS7Padding”, “BC”);中BC去掉,不知道行不行!可以试一下!!!

setTab(index) {
    
    
	let that = this;
	that.tabIndex = index;
	if (index == 1) {
    
    
		uni.login({
    
    
			provider: 'weixin',
			success: function(loginRes) {
    
    
				that.loginResCode = loginRes.code;
			}
		})
	}
},
getPhoneNumber: function(e) {
    
    
	console.log('aaaaaaaa', e)
	if (e.detail.errMsg != "getPhoneNumber:ok") {
    
    
		return console.log('用户拒绝请求')
	}
	let self = this;
	let fromData = {
    
    
		rawData: e.detail.encryptedData,
		iv: e.detail.iv,
		code: self.loginResCode
	}
	self.$api.wxLogin(fromData).then(res => {
    
    
		if (res.data.code == 200) {
    
    
			self.$store.commit('changeUserInfo', res.data.data);
			self.$store.commit('changeLoginStatus', true);
			self.$store.commit('changeToken', res.header.accesstoken || res.header.accessToken);
			// uni.navigateBack();
			var pages = getCurrentPages(); // 当前页面
			var beforePage = pages[pages.length - 2]; // 前一个页面
			if (beforePage) {
    
    
				uni.navigateBack()
			} else {
    
    
				uni.switchTab({
    
    
					url: '/pages/home/home'
				})
			}
		} else {
    
    
			uni.showModal({
    
    
				title: '提示',
				content: res.data.msg,
				showCancel: false,
				success: function(res) {
    
    
					if (res.confirm) {
    
    
						console.log('用户点击确定');
					} else if (res.cancel) {
    
    
						console.log('用户点击取消');
					}
				}
			});
		}
	})
},

猜你喜欢

转载自blog.csdn.net/weixin_45788691/article/details/128599597