微信小程序解密手机号:烦人的Input length must be multiple of 16 when decrypting with padded cipher

近期项目需要做一个微信小程序解密拿到手机号:
微信下程序授权登录拿到手机号的流程图:
在这里插入图片描述
小程序可以通过各种前端接口获取微信提供的开放数据。考虑到开发者服务器也需要获取这些开放数据,微信会对这些数据做签名和加密处理。开发者后台拿到开放数据后可以对数据进行校验签名和解密,来保证数据不被篡改。

签名校验以及数据加解密涉及用户的会话密钥 session_key。 开发者应该事先通过 wx.login 登录流程获取会话密钥 session_key 并保存在服务器。为了数据不被篡改,开发者不应该把 session_key 传到小程序客户端等服务器外的环境。

接口返回的加密数据(encryptedData) 进行对称解密。 解密算法如下:

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

开始撸代码:
1:先看看刚开始写的代码:
controller层:

  @PostMapping("/public/user/auth/phone")
    public RtnResult<Object> authPhone(    String encryData,String sessionKey,String iv) throws Exception {
        log.info("解密手机号,入参为【{}】",sessionKey,);
        return wxmpService.authPhone(String encryData,String sessionKey,String iv);
    }

service层:

    public RtnResult<Object> authPhone(String encryData, String sessionKey, String ivStr) throws Exception {
        String phone =decryptPhone(encryData, sessionKey, ivStr);
       log.info("通过seeionKey解密成功后的手机号:【{}】", phone);
       return RtnResult.success(phone);
    }

decryptPhone方法:

    public String decryptPhone( String encryptedData, String sessionKey, String ivStr) throws Exception {
        Base64 base64 = new Base64();
        byte[] encData = base64.decode(encryptedData);
        byte[] iv = base64.decode(ivStr);
        byte[] key = base64.decode(sessionKey);
        AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
        String mapStr = new String(cipher.doFinal(encData),"UTF-8");
        Map<String,Object> bodyMap = JacksonUtil.json2Map(mapStr);
        return (String) bodyMap.get("phoneNumber");
    }

开开心心的运行,以为大功告成,成功近在眼前。。。。。。嗨嗨嗨!!!
一运行,完了完了完了,报错了,问题出现在那?出了什么错呢???


String mapStr = new String(cipher.doFinal(encData),"UTF-8");//这一句出现异常

09:56:00.199 [http-nio-8080-exec-3] ERROR c.h.m.e.GlobalExceptionHandler - 系统异常信息被捕获
javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
	at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:936)
	at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:847)
	at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
	at javax.crypto.Cipher.doFinal(Cipher.java:2164)
	at com.hczt.mall.wx.service.WxmpService.decryptPhone(WxmpService.java:139)
	at com.hczt.mall.wx.service.WxmpService.authPhone(WxmpService.java:119)
	at com.hczt.mall.wx.controller.WxmpController.authPhone(WxmpController.java:44)
	at com.hczt.mall.wx.controller.WxmpController$$FastClassBySpringCGLIB$$fe73f753.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:746)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:112)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)

这句话的意思就是:当填充密码进行解密时,输入长度必须是16的倍数,意思就是加密的数据encryData的长度不是16的倍数

打印传过来的三个数据的长度:

 data长度:【157】,iv长度:【16】,key长度【16】//data的长度是157不是16的倍数

认真仔细查看,前台传过来的参数和后台接口的参数作比较:
前台传过来的的参数为:

encryData:7yMoGI85MIssud2hBeEpz9ib6BJ9epZVYYqNvqA+DPnhPfui1yeOh6+4AMlIpidzMjlKV3wr6eEqXR2+qAk7WmezN7CO7i/6HZNFPy+ZZ/p8RTyVSbxwytOnJkSf49cb/v7cgX10BnuJ4M6n7ORJY1EBVg7iBWh9IPaWCuBxogBBX3NScuFc4CFXn1loagb2G0bTgiY1CKFnrvpiOnMY4g==

后台接受的参数为:

解密手机号,encaryData入参为【7yMoGI85MIssud2hBeEpz9ib6BJ9epZVYYqNvqA DPnhPfui1yeOh6 4AMlIpidzMjlKV3wr6eEqXR2 qAk7WmezN7CO7i/6HZNFPy ZZ/p8RTyVSbxwytOnJkSf49cb/v7cgX10BnuJ4M6n7ORJY1EBVg7iBWh9IPaWCuBxogBBX3NScuFc4CFXn1loagb2G0bTgiY1CKFnrvpiOnMY4g==】

问题原因根本:
一看就发现问题所在,原来是"+"没有了。因为符号“+”和符号“/”是不允许出现在URL中的

解决办法:
那么不把数据放在路径上了,把数据封装到一个对象里,用@RequestBody来接受参数,修改controller层
第一步:增加一个对象:

import lombok.Data;
@Data
public class WxAuthPhone {
    String encryData;
    String sessionKey;
    String iv;
}

第二步:修改controller层

    @PostMapping("/public/user/auth/phone")
    public RtnResult<Object> authPhone(@RequestBody WxAuthPhone wxAuthPhone) throws Exception {
        log.info("解密手机号,入参为【{}】",wxAuthPhone);
        return wxmpService.authPhone(wxAuthPhone);
    }

第三步:修改sevice层

public RtnResult<Object> authPhone(WxAuthPhone wxAuthPhone) throws Exception {
    String phone =decryptPhone(wxAuthPhone.getEncryData(), wxAuthPhone.getSessionKey(), wxAuthPhone.getIv());
    log.info("通过seeionKey解密成功后的手机号:【{}】", phone);
    return RtnResult.success(phone);
}

测试结果:

手机号解密成功,手机号为【17865342342】
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值