首页 > 微信应用  > 

微信开发之消息体签名和加解密

微信开发之消息体签名和加解密
前几篇主要是微信开发的准备工作,也没有什么技术含量。在第一篇和第二篇中,我主要讲的是使用花生壳来配合vs进行代码调试,也一度被园友吐槽本人是花生壳请来的逗比,没办法,为了和花生壳划清界限,在本篇进入正文前,为大家介绍一个比花生壳更好用的工具ngrok,ngrok的好处我就不在此具体说明了,毕竟不是本文的重点

  前几篇主要是微信开发的准备工作,也没有什么技术含量。在第一篇和第二篇中,我主要讲的是使用花生壳来配合vs进行代码调试,也一度被园友吐槽本人是花生壳请来的逗比,没办法,为了和花生壳划清界限,在本篇进入正文前,为大家介绍一个比花生壳更好用的工具ngrok,ngrok的好处我就不在此具体说明了,毕竟不是本文的重点

   出于安全考虑,微信公众平台在10月份的时候加入了消息体的加解密功能,首先,需要先验证签名,用于公众平台和公众账号验证消息体的正确性,其次,针对推送给公众号的普通消息和事件消息,以及推送给设备公众账号的设备进行加密,最后,公众号对密文消息的回复也需要加密。启用加解密功能后,公众平台服务器在向公众号服务器配置地址推送消息时,url将新增加两个参数,一个是加密类型一个是消息体签名,并以此来体现新功能。加密算法采用AES。关于明文模式,兼容模式,安全模式的说明,大家请参考官方文档.

验证消息真实性和加解密的帮助类官方提供的有demo,再次不详细讲述了,下载下来可以直接调用,下面请看代码:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Security.Cryptography;using System.IO;using System.Net;namespace WxApi{ public class Cryptography { public static UInt32 HostToNetworkOrder(UInt32 inval) { UInt32 outval = 0; for (int i = 0; i < 4; i++) outval = (outval << 8) + ((inval >> (i * 8)) & 255); return outval; } public static Int32 HostToNetworkOrder(Int32 inval) { Int32 outval = 0; for (int i = 0; i < 4; i++) outval = (outval << 8) + ((inval >> (i * 8)) & 255); return outval; } /// <summary> /// 解密方法 /// </summary> /// <param name="Input">密文</param> /// <param name="EncodingAESKey"></param> /// <returns></returns> /// public static string AES_decrypt(String Input, string EncodingAESKey, ref string appid) { byte[] Key; Key = Convert.FromBase64String(EncodingAESKey + "="); byte[] Iv = new byte[16]; Array.Copy(Key, Iv, 16); byte[] btmpMsg = AES_decrypt(Input, Iv, Key); int len = BitConverter.ToInt32(btmpMsg, 16); len = IPAddress.NetworkToHostOrder(len); byte[] bMsg = new byte[len]; byte[] bAppid = new byte[btmpMsg.Length - 20 - len]; Array.Copy(btmpMsg, 20, bMsg, 0, len); Array.Copy(btmpMsg, 20 + len, bAppid, 0, btmpMsg.Length - 20 - len); string oriMsg = Encoding.UTF8.GetString(bMsg); appid = Encoding.UTF8.GetString(bAppid); return oriMsg; } public static String AES_encrypt(String Input, string EncodingAESKey, string appid) { byte[] Key; Key = Convert.FromBase64String(EncodingAESKey + "="); byte[] Iv = new byte[16]; Array.Copy(Key, Iv, 16); string Randcode = CreateRandCode(16); byte[] bRand = Encoding.UTF8.GetBytes(Randcode); byte[] bAppid = Encoding.UTF8.GetBytes(appid); byte[] btmpMsg = Encoding.UTF8.GetBytes(Input); byte[] bMsgLen = BitConverter.GetBytes(HostToNetworkOrder(btmpMsg.Length)); byte[] bMsg = new byte[bRand.Length + bMsgLen.Length + bAppid.Length + btmpMsg.Length]; Array.Copy(bRand, bMsg, bRand.Length); Array.Copy(bMsgLen, 0, bMsg, bRand.Length, bMsgLen.Length); Array.Copy(btmpMsg, 0, bMsg, bRand.Length + bMsgLen.Length, btmpMsg.Length); Array.Copy(bAppid, 0, bMsg, bRand.Length + bMsgLen.Length + btmpMsg.Length, bAppid.Length); return AES_encrypt(bMsg, Iv, Key); } private static string CreateRandCode(int codeLen) { string codeSerial = "2,3,4,5,6,7,a,c,d,e,f,h,i,j,k,m,n,p,r,s,t,A,C,D,E,F,G,H,J,K,M,N,P,Q,R,S,U,V,W,X,Y,Z"; if (codeLen == 0) { codeLen = 16; } string[] arr = codeSerial.Split(&#39;,&#39;); string code = ""; int randValue = -1; Random rand = new Random(unchecked((int)DateTime.Now.Ticks)); for (int i = 0; i < codeLen; i++) { randValue = rand.Next(0, arr.Length - 1); code += arr[randValue]; } return code; } private static String AES_encrypt(String Input, byte[] Iv, byte[] Key) { var aes = new RijndaelManaged(); //秘钥的大小,以位为单位 aes.KeySize = 256; //支持的块大小 aes.BlockSize = 128; //填充模式 aes.Padding = PaddingMode.PKCS7; aes.Mode = CipherMode.CBC; aes.Key = Key; aes.IV = Iv; var encrypt = aes.CreateEncryptor(aes.Key, aes.IV); byte[] xBuff = null; using (var ms = new MemoryStream()) { using (var cs = new CryptoStream(ms, encrypt, CryptoStreamMode.Write)) { byte[] xXml = Encoding.UTF8.GetBytes(Input); cs.Write(xXml, 0, xXml.Length); } xBuff = ms.ToArray(); } String Output = Convert.ToBase64String(xBuff); return Output; } private static String AES_encrypt(byte[] Input, byte[] Iv, byte[] Key) { var aes = new RijndaelManaged(); //秘钥的大小,以位为单位 aes.KeySize = 256; //支持的块大小 aes.BlockSize = 128; //填充模式 //aes.Padding = PaddingMode.PKCS7; aes.Padding = PaddingMode.None; aes.Mode = CipherMode.CBC; aes.Key = Key; aes.IV = Iv; var encrypt = aes.CreateEncryptor(aes.Key, aes.IV); byte[] xBuff = null; #region 自己进行PKCS7补位,用系统自己带的不行 byte[] msg = new byte[Input.Length + 32 - Input.Length % 32]; Array.Copy(Input, msg, Input.Length); byte[] pad = KCS7Encoder(Input.Length); Array.Copy(pad, 0, msg, Input.Length, pad.Length); #endregion #region 注释的也是一种方法,效果一样 //ICryptoTransform transform = aes.CreateEncryptor(); //byte[] xBuff = transform.TransformFinalBlock(msg, 0, msg.Length); #endregion using (var ms = new MemoryStream()) { using (var cs = new CryptoStream(ms, encrypt, CryptoStreamMode.Write)) { cs.Write(msg, 0, msg.Length); } xBuff = ms.ToArray(); } String Output = Convert.ToBase64String(xBuff); return Output; } private static byte[] KCS7Encoder(int text_length) { int block_size = 32; // 计算需要填充的位数 int amount_to_pad = block_size - (text_length % block_size); if (amount_to_pad == 0) { amount_to_pad = block_size; } // 获得补位所用的字符 char pad_chr = chr(amount_to_pad); string tmp = ""; for (int index = 0; index < amount_to_pad; index++) { tmp += pad_chr; } return Encoding.UTF8.GetBytes(tmp); } /** * 将数字转化成ASCII码对应的字符,用于对明文进行补码 * * @param a 需要转化的数字 * @return 转化得到的字符 */ static char chr(int a) { byte target = (byte)(a & 0xFF); return (char)target; } private static byte[] AES_decrypt(String Input, byte[] Iv, byte[] Key) { RijndaelManaged aes = new RijndaelManaged(); aes.KeySize = 256; aes.BlockSize = 128; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.None; aes.Key = Key; aes.IV = Iv; var decrypt = aes.CreateDecryptor(aes.Key, aes.IV); byte[] xBuff = null; using (var ms = new MemoryStream()) { using (var cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Write)) { byte[] xXml = Convert.FromBase64String(Input); byte[] msg = new byte[xXml.Length + 32 - xXml.Length % 32]; Array.Copy(xXml, msg, xXml.Length); cs.Write(xXml, 0, xXml.Length); } xBuff = decode2(ms.ToArray()); } return xBuff; } private static byte[] decode2(byte[] decrypted) { int pad = (int)decrypted[decrypted.Length - 1]; if (pad < 1 || pad > 32) { pad = 0; } byte[] res = new byte[decrypted.Length - pad]; Array.Copy(decrypted, 0, res, 0, decrypted.Length - pad); return res; } }}

微信开发之消息体签名和加解密由讯客互联微信应用栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“微信开发之消息体签名和加解密