原创声明:本文为作者原创,未经允许不得转载,经授权转载需注明作者和出处
通过wx.getUserInfo()的success回调得到的加密数据( encryptedData )
对加密数据( encryptedData )解密后可得到openId和unionId。
如何解密,官方文档是这样解释的!
首次看到如上解密说明时,我只知道encryptedData和session_key获得方式。
session_key在上篇有介绍,如下:
获得session_key和openId(加解密、签名系列)
1:AES是什么?
2:128是什么?
3:CBC是什么?
4:初始向量iv是做什么用的?
5:数据采用PKCS#7填充什么意思?
6:1,2,3,4条分别说明的算法,密文,密钥,初始向量iv如何组合使用?
7:Base64_Decode又是什么?
美国国家标准技术研究所在2001年发布了高级加密标准(AES)。
AES是基于数据块的加密方式,
即,每次处理的数据是一块(16字节),当数据不是16字节的倍数时填充,
这就是所谓的分组密码(区别于基于比特位的流密码),16字节是分组长度。
AES是一个对称分组密码算法。
由于每一步操作都是可逆的,按照相反的顺序进行解密即可恢复明文,解密过程分别为对应的逆操作。
分组:AES把看的见的信息(明文),分成很多相同组,对每组进行加密,然后再合成。
AES根据使用的密码(密钥)位数,AES最常见的有3种方案,用以适应不同的场景要求,
分别是AES-128、AES-192和AES-256。
微信小程序使用的是AES-128。
AES是基于数据块的加密方式,也就是说,每次处理的数据是一块(16字节),
当数据不是16字节的倍数时填充,这就是所谓的分组密码(区别于基于比特位的流密码),16字节是分组长度。
即,AES把看的见的信息(明文),分成很多相同组(明文块),一般为128位(16字节)。
对每组进行单独加密,然后再把各加密块拼接成一条密文。
ECB
:是一种基础的加密方式,密文被分割成分组长度相等的块(不足补齐),然后单独一个个加密,一个个输出组成密文。
CBC
:是一种循环模式,前一个分组的密文和当前分组的明文异或操作后再加密,这样做的目的是增强破解难度。
CFB/OFB
实际上是一种反馈模式,目的也是增强破解的难度。
处理方式:
密文快[0..n] = 加密算法(明文块[0…n],密钥)
特点:
1:相同的输入产生相同的输出。
2:不能隐藏明文的模式,可能对明文进行主动攻击;
AES默认的,最简单,但安全性不够,所以微信用了改良版CBC。
处理方式:
密文快[0] = 加密算法(初始向量IV
,明文块0,密钥)
其他密文块[1…n]=加密算法(之前的密文块
,明文快,密钥)
这个模式是链式的,后一块需要前一块做基础,第一块需要一个需要初始化向量IV做基础。
相同的输入产生不同的输出。
能看到的数据是“明文+IV”或“明文+前一个密文”的乱码,所以能隐藏明文。
总结:
安全性比第一种好,所以微信小程序用AES-CBC模式,所以需要IV向量
。
密文 =AES(明文、密钥、初始向量参数)
明文=AES(密文、密钥、初始向量参数)
因为AES的算法是把明文分组再处理的,他要求每个分组(16字节)是“满”的,即明文长度必须被16字节整除。
所以明文最后不足的16字节的要先进行数据填充,把不足16字节的最后一组补成16字节。
所以可知:明文先填充,再AES加密。
例如:明文171字节,最后一节为11个字节,需要填充5个字节(16-11)
PKCS#7
是其中一种。PKCS #7 字符串由一个字节序列组成,每个字节填充该字节序列的长度。
假定块长度为 8,数据长度为 9,
则填充用八位字节数等于 7,数据等于 FF FF FF FF FF FF FF FF FF:
数据: FF FF FF FF FF FF FF FF FF
PKCS7 填充: FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07
Base64是网络上最常见的用于字节代码的编码方式之一(一个字母就是一字节byte)
采用Base64编码具有不可读性,即所编码的数据不会被人用肉眼所直接看到。
Base64编码非常适合HTTP环境下传递较长的标识信息(传输8Bit字节代码)
其他应用程序中,也常常需要把二进制数据编码为适合放在URL中的形式
其实迅雷的“专用地址”也是用Base64”加密”的,其过程如下:
1、在http://地址的前后分别添加AA和ZZ
2、对新的字符串进行Base64编码
把迅雷地址还原为http地址,只需要用Base64解码,然后去掉头尾的AA和ZZ即可。
迅雷地址Base编码案例,详见此文:
http://www.wxappclub.com/topic/711
Base64_Encode(目标密文)=encryptedData
(wx.getUserInfo得到的)
Base64_Encode(AES密钥)=session_key
Base64_Encode(初始向量)=iv
所以:
即目标密文=Base64_Decode(encryptedData
)
即密钥aeskey=Base64_Decode(session_key
)
即初始向量=Base64_Decode(iv
)
注意:通过如下官方提供的代码demo可知,iv也进行了Base64的解码。
文档上并未说明
通过上边的分析,我们知道:
微信小程序用的AES加密算法、AES-128的方案、CBC的分组加密模式(此模式需要IV初始化向量)
AES加密敏感数据之前,先用PKCS#7填充“用户敏感数据”最后不足16字节的部分。
AES对密文解密后,需用PKCS#7出去填充才能得到真正“用户敏感数据”
知道:
openId,union等敏感数据=AES-128-CBC(密文,密钥,初始向量iv)
第1条:描述的是加密算法和数据填充方式
第2条:描述的是如何得到密文(目标密文=Base64_Decode(encryptedData))
第3条:描述的是如何得到密钥(密钥aeskey=Base64_Decode(session_key))
第4条:描述的是如何得到初始向量iv
上述涉及的数据:
encryptedData(来自第2条)
通过wx.getUserInfo()的success回调得到的
iv(来自第4条)
通过wx.getUserInfo()的success回调得到的
session_key (来自第3条)
1:通过wx.login()的success回调得到的js_code
2:通过js_code、appid、secret得到session_key
详情查看如下文章
获得session_key和openId(加解密、签名系列)
1:对敏感用户信息“目标明文”用psck#7号填充得到“填充文”
2:AES-128-CBC(填充文,密钥,初始向量)=>目标密文
3:Base64_Encode(目标密文)=>encryptedData
4:Base64_Encode(初始向量)=>iv
5:Base64_Encode(密钥)=session_key
1:通过wx.getUserInfo()获得密文crypteddata,iv
2:通过wx.login()得到的js_code和http接口得到session_key(详情请看)
3:Base64_Decode(encryptedData)=>目标密文
4:Base64_Decode(session_key)=>即密钥aeskey
5:Base64_Decode(iv)=>初始向量
6:AES-128-CBC(目标密文,密钥,初始向量)=>填充文
7:用psck#7对填充文去除填充得到敏感的用户信息“目标明文”