收藏
回答

小程序getPhoneNumber 解密手机号时,偶尔会出现填充无效,无法被移除

问题模块 框架类型 问题类型 API/组件名称 终端类型 微信版本 基础库版本
API和组件 小程序 Bug getPhoneNumber 工具 v1.02.1808300 2.0.0

客户端

getPhoneNumber: function (e) {

let that=this;

wx.login({

success: function (res) {

if (e.detail.errMsg == 'getPhoneNumber:fail user deny') {

wx.navigateTo({

url: '../../pages/userLogin/userLogin',

});

} else {

if (e.detail.errMsg == 'getPhoneNumber:fail:cancel to confirm login') {

wx.navigateTo({

url: '../../pages/userLogin/userLogin?url='+that.data.url

});

}

else {

//console.log(res.code);

wx.request({

url: api.AESdecrypt,

data: {

'encryptedDataStr': e.detail.encryptedData,

'code': res.code,

'iv': e.detail.iv

},

method: 'post',

header: { 'content-type': 'application/x-www-form-urlencoded' },

success: function (data) {

console.log(data);

app.globalData.userInfo = data.data.data;

setTimeout(function(){

wx.navigateBack({ changed: true });//返回上一页

},500);

},

error: function () {

tip.showToast('error');

},

fail: function (err) {

tip.showToast(err);

}

})

}

}

}

});

},


服务端

try

            {

                string encryptedDataStr = System.Web.HttpContext.Current.Request["encryptedDataStr"],

                    code = System.Web.HttpContext.Current.Request["code"],

                    iv = System.Web.HttpContext.Current.Request["iv"];

                ReturnData resultMsg = new ReturnData();

                resultMsg.state = (int)StatusCodeEnum.Success;

                resultMsg.message = StatusCodeEnum.Success.GetEnumText();

                string strresult = "";

                string Appid = "Appid";

                string Secret = "Secret ";

                string grant_type = "authorization_code";

                GetUsersHelper GetUsersHelper = new Controllers.GetUsersHelper();

                //向微信服务端 使用登录凭证 code 获取 session_key 和 openid  

                string url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + Appid + "&secret=" + Secret + "&js_code=" + code + "&grant_type=" + grant_type;

                Stream s_re = WebRequest.Create(url).GetResponse().GetResponseStream();

                StreamReader sr = new StreamReader(s_re, Encoding.UTF8);

                string strLine = sr.ReadToEnd();

                sr.Close();


                //将字符串转换为json格式 

                JObject jo = (JObject)JsonConvert.DeserializeObject(strLine);

                result res = new result();

                try

                {

                    //微信服务器验证成功 

                    res.openid = jo["openid"].ToString();

                    res.session_key = jo["session_key"].ToString();

                }

                catch (Exception)

                {

                    //微信服务器验证失败 

                    res.errcode = jo["errcode"].ToString();

                    res.errmsg = jo["errmsg"].ToString();

                    WriteInfo(res.errmsg);

                }

                if (!string.IsNullOrEmpty(res.openid))

                {

                    //用户数据解密 

                    strresult = GetUsersHelper.AESDecrypt(encryptedDataStr, res.session_key,iv);//.AES_decrypt(encryptedDataStr,res.session_key,iv);//

                    JObject jos = (JObject)JsonConvert.DeserializeObject(strresult);

                    ResultInfo ress = new ResultInfo();

                    ress.phoneNumber = jos["phoneNumber"].ToString();

                    var model = Ioc.Get<IUserRepository>().FindMobile(ress.phoneNumber);

                    resultMsg.data = model;

                }

                else

                {

                    strresult = null;

                    resultMsg.data = strresult;

                }

                return resultMsg;

            }

            catch (Exception ex)

            {

                WriteInfo(ex.Message);

                return new ReturnData

                {

                    state=200,

                    message="error",

                    data=null

                };

            }

解密.net

public string AESDecrypt(string inputdata, string AesKey, string AesIV)

        {

            try

            {

                RijndaelManaged rijalg = new RijndaelManaged();

                //-----------------    

                //设置 cipher 格式 AES-128-CBC    


                rijalg.KeySize = 128;


                rijalg.Padding = PaddingMode.PKCS7;

                rijalg.Mode = CipherMode.CBC;


                rijalg.Key = Convert.FromBase64String(AesKey);

                rijalg.IV = Convert.FromBase64String(AesIV);



                byte[] encryptedData = Convert.FromBase64String(inputdata);

                //解密    

                ICryptoTransform decryptor = rijalg.CreateDecryptor(rijalg.Key, rijalg.IV);


                string result;


                using (MemoryStream msDecrypt = new MemoryStream(encryptedData))

                {

                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))

                    {

                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))

                        {


                            result = srDecrypt.ReadToEnd();

                        }

                    }

                }


                return result;  


            }

            catch (Exception ex)

            {

                ApiUserController apis = new ApiUserController();

                apis.WriteInfo("jiemi"+ex.Message);

                return null;

            }

        }


回答关注问题邀请回答
收藏

4 个回答

  • 大刚
    大刚
    2019-11-28

    我来解答下吧,这问题我也遇到过,问题出在哪里呢,就出在点击 button 的地方,没有 wx.login 得到code 的时候,iv和encryptedData 就已存在一个session_key ,和之后得到的session_key 就不同了,我第一的逻辑是在点击button按钮的时候重新获取code,发送请求给服务器,让服务器去解密新的session_key和opendid 这样会有一定的几率导致 登录态session_key 更新,后台会报 解密微信用户信息异常  :javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption   当然这个报错是有一定的概率的,这就是楼主的情况 。 我之后想过 登录之后再调用一次 wx.login 方法 获取下code 再等点击获取电话号码按钮的时候 把这个code传递给后台,但是这个code 会有 5分钟的有效期 超过5分钟就会报 invalid code  失效的code  最后想到了 微信的api wx.checksession方法,但是该方法只会去校验 session_key是否有效,并不能去校验code 是否过期 ,由于session_key的过期时间官方没有给,code的过期时间只有5分钟,所以还得转变思路,就是在使用wx.checksession的时候在成功的回调里 说明session_key是有效的,所以就给后台传递一个有效的标识,让后台使用之前的session_key,带上点击事件e里面获取的iv 和 encryptedData 来解密用户的电话号码  在失败的回调里,说明这个时候的session_key失效了,就走楼主的逻辑,重新调用wx.login方法,获取最新的code 交给后台去解密有效的session_key,最终解决该问题


    //如果用户点击确定就采取的操作

    if (e.detail.errMsg === 'getPhoneNumber:ok') {

    //测试会话是否有效 code是否过期

    wx.checkSession({

    success(){

    //session_key 未过期,并且在本生命周期一直有效 发送请求获取电话号码 usesessionkey为session_key是否过期的标识  getPhone 是通用的进行解密电话号码的方法

    that.getPhone(that.data.usesessionkey, e.detail.iv, e.detail.encryptedData, that);

    console.log('success');

    },

    fail(){

    console.log('fail');

    // session_key 已经失效,需要重新执行登录流程  获取新的code 发送给后台去获取最新的sesson_key

    wx.login({

    success(res) {

    if (res.code){

    that.getPhone(res.code, e.detail.iv, e.detail.encryptedData, that);

    }

    }

    })

    }

    })

    }





    2019-11-28
    赞同
    回复
  • Microestc ® ZngL
    Microestc ® ZngL
    2019-11-10

    已经找到根源了,详情去看我博客吧 微信小程序加密解密 C# 以及 填充无效,无法被移除错误的解决方案 Padding is invalid and cannot be removed

    2019-11-10
    赞同
    回复
  • 眼泪的错觉
    眼泪的错觉
    2018-09-29

    求解

    2018-09-29
    赞同
    回复 1
    • 执念太深
      执念太深
      2018-09-29

      先在onload里调用https://api.weixin.qq.com/sns/jscode2session?appid=" + Appid + "&secret=" + Secret + "&js_code=" + code + "&grant_type=" + grant_type;获取session_key,并记录,然后再进行解密,解密时把session_key一同传过去

      2018-09-29
      回复
  • 右手握拍
    右手握拍
    2018-09-27

    我也是遇到这种情况,不知道怎么解决了

    2018-09-27
    赞同
    回复 2
    • 执念太深
      执念太深
      2018-09-29

      先在onload里调用https://api.weixin.qq.com/sns/jscode2session?appid=" + Appid + "&secret=" + Secret + "&js_code=" + code + "&grant_type=" + grant_type;获取session_key,并记录,然后再进行解密,解密时把session_key一同传过去

      2018-09-29
      回复
    • Ray
      Ray
      2019-11-01回复执念太深
      能不能解释一下你这样解决的思路?
      2019-11-01
      回复
登录 后发表内容