匿名通过本文主要向大家介绍了微信开发,消息体,签名,加解密等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com
前几篇主要是微信开发的准备工作,也没有什么技术含量。在第一篇和第二篇中,我主要讲的是使用花生壳来配合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(','); 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 Inp

