订阅消息加解密指南
订阅消息加解密指南
概述
微伴助手在推送消息给企业时,会对消息内容做AES加密,以JSON格式POST到企业应用的URL上。
企业在被动响应时,也需要对数据加密,以JSON返回给微伴助手。
本章节即是对加解密方法的说明。
阅读本章节前,需要了解以下术语:
- msg_signature: 消息签名,用于验证请求是否来自为微伴助手(防止攻击者伪造)。
- EncodingAESKey:用于消息体的加密,长度固定为43个字符,从a-z, A-Z, 0-9共62个字符中选取,是AESKey的Base64编码。解码后即为32字节长的AESKey
AESKey=Base64_Decode(EncodingAESKey + "=")
- AESKey:AES算法的密钥,长度为32字节。AES采用CBC模式,数据采用PKCS#7填充至32字节的倍数;IV初始向量大小为16字节,取AESKey前16字节,详见:http://tools.ietf.org/html/rfc2315
- msg:为消息体明文,格式为JSON
- msg_encrypt:明文消息msg加密处理后的Base64编码。
使用已有库
初始化加解密类
WBMsgCrypt wbcpt(sToken,sEncodingAESKey,sReceiveId);
要求传参数sToken,sEncodingAESKey,sReceiveId。
sToken,sEncodingAESKey即在微伴助手配置的Token、EncodingAESKey;ReceiveId表示CorpId。
验证URL函数
本函数实现:
- 签名校验
- 解密数据包,得到明文消息内容
int VerifyURL(const string &sMsgSignature, const string &sTimeStamp, const string &sNonce, const string &sEchoStr, string &sReplyEchoStr);
- 参数说明
参数 | 必须 | 说明 |
---|---|---|
sMsgSignature | 是 | 从接收消息的URL中获取的msg_signature参数 |
sTimeStamp | 是 | 从接收消息的URL中获取的timestamp参数 |
sNonce | 是 | 从接收消息的URL中获取的nonce参数 |
sEchoStr | 是 | 从接收消息的URL中获取的echostr参数。注意,此参数必须是urldecode后的值 |
sReplyEchoStr | 是 | 解密后的明文消息内容,用于回包。注意,必须原样返回,不要做加引号或其它处理 |
解密函数
本函数实现:
- 签名校验
- 解密数据包,得到明文消息结构体
int DecryptMsg(const string &sMsgSignature, const string &sTimeStamp, const string &sNonce, const string &sPostData, string &sMsg);
- 参数说明
参数 | 必须 | 说明 |
---|---|---|
sMsgSignature | 是 | 从接收消息的URL中获取的msg_signature参数 |
sTimeStamp | 是 | 从接收消息的URL中获取的timestamp参数 |
sNonce | 是 | 从接收消息的URL中获取的nonce参数 |
sPostData | 是 | 从接收消息的URL中获取的整个post数据 |
sMsg | 是 | 用于返回解密后的msg,以json组织 |
加密函数
本函数实现:
- 加密明文消息结构体
- 生成签名
- 构造被动响应包
int EncryptMsg(const string &sReplyMsg, const string &sTimeStamp, const string &sNonce, string &sEncryptMsg);
- 参数说明
参数 | 必须 | 说明 |
---|---|---|
sReplyMsg | 是 | 返回的消息体原文 |
sTimeStamp | 是 | 时间戳,调用方生成 |
sNonce | 是 | 随机数,调用方生成 |
sEncryptMsg | 是 | 用于返回的密文,以json组织 |
原理详解
消息体签名校验
为了让企业确认调用来自微伴助手,微伴助手在回调给接收消息url时会带上消息签名,以参数msg_signature标识,企业需要验证此参数的正确性后再解密。
验证步骤如下:
计算签名
dev_msg_signature=sha1(sort(token、timestamp、nonce、msg_encrypt))。
sort的含义是将参数值按照字母字典排序,然后从小到大拼接成一个字符串
sha1处理结果要编码为可见字符,编码的方式是把每字节散列值打印为%02x(即16进制,C printf语法)格式,全部小写比较dev_msg_signature和msg_signature是否相等,相等则表示验证通过
在被动响应消息时,企业同样需要用如上方法生成签名并传给微伴助手
明文msg的加密过程
拼接明文字符串
rand_msg = random(16B) + msg_len(4B) + msg + corp_id
明文字符串由16个字节的随机字符串、4个字节的msg长度、明文msg和corp_id拼接组成。其中msg_len为msg的字节数,网络字节序;corp_id表示公司id。
对明文字符串加密并Base64编码
msg_encrypt = Base64_Encode(AES_Encrypt(rand_msg))
将明文字符串AESKey加密后,再进行Base64编码,即获得密文msg_encrypt。
密文解密得到msg的过程
对密文BASE64解码
aes_msg=Base64_Decode(msg_encrypt)
使用AESKey做AES-256-CBC解密
rand_msg=AES_Decrypt(aes_msg)
去掉rand_msg头部的16个随机字节和4个字节的msg_len,截取msg_len长度的部分即为msg,剩下的为尾部的corp_id
验证解密后的corp_id、msg_len。~~~~