阿哥论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博账号登陆

只需一步,快速开始

搜索
查看: 173|回复: 0

消息体签名与加解密-技术方案

[复制链接]

升级  30.33%

举人

Rank: 3Rank: 3

积分
291
 楼主| 发表于 2015-4-11 11:55:14 | 显示全部楼层 |阅读模式
消息体签名与加解密-技术方案
阅读须知1. EncodingAESKey长度固定为43个字符,从a-z,A-Z,0-9共62个字符中选取,公众帐号可以在公众平台的开发者中心的服务器配置修改;
2. AES密钥:AESKey=Base64_Decode(EncodingAESKey + “=”),EncodingAESKey尾部填充一个字符的“=”, 用Base64_Decode生成32个字节的AESKey;
3. AES采用CBC模式,秘钥长度为32个字节,数据采用PKCS#7填充;PKCS#7:K为秘钥字节数(采用32),buf为待加密的内容,N为其字节数。Buf需要被填充为K的整数倍。在buf的尾部填充(K-N%K)个字节,每个字节的内容是(K- N%K);
尾部填充
01 if ( N%K==(K-1))
0202 if ( N%K==(K-2))
030303 if ( N%K==(K-3))
... ...
KK....KK (K个字节) if ( N%K==0)
具体详见:http://tools.ietf.org/html/rfc2315
5. 出于安全考虑,公众平台网站提供了修改EncodingAESKey的功能(在EncodingAESKey可能泄漏时进行修改),所以建议公众账号保存当前的和上一次的EncodingAESKey,若当前EncodingAESKey生成的AESKey解密失败,则尝试用上一次的AESKey的解密。回包时,用哪个AESKey解密成功,则用此AESKey加密对应的回包
6. 兼容模式消息体同时存在明文和密文,消息体会增至以前的3倍左右,开发者注意检查系统防止因消息变长和URL参数增加而出现接收错误
7. 微信团队提供了多种语言的示例代码(包括PHPJavaC++PythonC#),请开发者尽量使用示例代码。(../static/assets/a5a22f38cb60228cb32ab61d9e4c414b.zip )

下面以普通文本消息为例,详细说明公众平台对消息体加解密的方法和流程,其它普通消息和事件消息的加解密可以此类推。
公众账号接收用户消息消息体加密
现有消息为明文,格式如下:
msg = <xml>        <ToUserName><![CDATA[toUser]]></ToUserName>        <FromUserName><![CDATA[fromUser]]></FromUserName>         <CreateTime>1348831860</CreateTime>        <MsgType><![CDATA[text]]></MsgType>        <Content><![CDATA[this is a test]]></Content>        <MsgId>1234567890123456</MsgId></xml>
兼容模式期间同时保留明文和密文,消息格式如下:
new_msg=<xml>        <ToUserName><![CDATA[toUser]]></ToUserName>        <FromUserName><![CDATA[fromUser]]></FromUserName>         <CreateTime>1348831860</CreateTime>        <MsgType><![CDATA[text]]></MsgType>        <Content><![CDATA[this is a test]]></Content>        <MsgId>1234567890123456</MsgId>        <Encrypt><![CDATA[msg_encrypt]]</Encrypt></xml>安全模式下,消息体只有密文,格式如下:
new_msg=<xml>         <ToUserName><![CDATA[toUser]]</ToUserName>       <Encrypt><![CDATA[msg_encrypt]]</Encrypt></xml>其中,msg_encrypt = Base64_Encode( AES_Encrypt[ random(16B) + msg_len(4B) + msg + $appId] )
AES加密的buf由16个字节的随机字符串、4个字节的msg_len(网络字节序)、msg和$AppId组成,其中msg_len为msg的长度,$AppId为公众帐号的AppId
AESKey =Base64_Decode(EncodingAESKey  + “=”),32个字节
url上增加参数encrypt_type,encrypt_type的值为raw时表示为不加密,encrypt_type的值为aes时,表示aes加密(暂时只有raw和aes两种值),无encrypt_type参数同样表示不加密

消息体签名
为了验证消息体的合法性,公众平台新增消息体签名,开发者可用以验证消息体的真实性,并对验证通过的消息体进行解密
在url上增加参数:msg_signature
msg_signature=sha1(sort(Token、timestamp、nonce, msg_encrypt))
参数说明
Token 公众平台上,开发者设置的Token
timestamp URL上原有参数,时间戳
nonce URL上原有参数,随机数
msg_encrypt 前文描述密文消息体

消息体验证和解密
开发者先验证消息体签名的正确性,验证通过后,再对消息体进行解密。

验证方式
1. 开发者计算签名,dev_msg_signature=sha1(sort(Token、timestamp、nonce, msg_encrypt))
2. 比较dev_msg_signature和URL上带的msg_signature是否相等,相等则表示验证通过

解密方式如下:
1. aes_msg=Base64_Decode(msg_encrypt)
2. rand_msg=AES_Decrypt(aes_msg)
3. 验证尾部$AppId是否是自己的AppId,相同则表示消息没有被篡改,这里进一步加强了消息签名验证
4. 去掉rand_msg头部的16个随机字节,4个字节的msg_len,和尾部的$AppId即为最终的xml消息体

公众账号向用户回复消息如果url上无encrypt_type或者其值为raw,则回复明文,否则按照上述的加密算法加密回复密文。兼容模式期间公众账号回复明文或密文均可(不要两种类型都回)
回复消息体的签名与加密
现有消息格式:
msg=<xml>         <ToUserName><![CDATA[toUser]]></ToUserName>         <FromUserName><![CDATA[fromUser]]></FromUserName>         <CreateTime>12345678</CreateTime>         <MsgType><![CDATA[text]]></MsgType>         <Content><![CDATA[你好]]></Content></xml>
加密后消息格式:
new_msg=<xml>        <Encrypt><![CDATA[msg_encrypt]]></Encrypt>        <MsgSignature><![CDATA[msg_signature]]></MsgSignature>        <TimeStamp>timestamp</TimeStamp>        <Nonce><![CDATA[nonce]]></Nonce></xml> 其中,msg_encrypt=Base64_Encode(AES_Encrypt [random(16B)+ msg_len(4B) + msg + $AppId])
random(16B)为16字节的随机字符串;msg_len为msg长度,占4个字节(网络字节序),$AppId为公众账号的AppId
AESKey =Base64_Decode(EncodingAESKey  + “=”),32个字节
msg_signature=sha1(sort(Token、timestamp、nonce, msg_encrypt))
timestamp、nonce回填请求中的值或者重新生成均可

消息体签名与加解密-技术方案
摘自:http://mp.weixin.qq.com/wiki/2/3478f69c0d0bbe8deb48d66a3111ff6e.html

您需要登录后才可以回帖 登录 | 立即注册 新浪微博账号登陆

本版积分规则

快速回复 返回顶部 返回列表