#region Apache License Version 2.0 /*---------------------------------------------------------------- Copyright 2019 Jeffrey Su & Suzhou Senparc Network Technology Co.,Ltd. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Detail: https://github.com/JeffreySu/WeiXinMPSDK/blob/master/license.md ----------------------------------------------------------------*/ #endregion Apache License Version 2.0 /*---------------------------------------------------------------- 文件名:Cryptography.cs 文件功能描述:加解密算法 创建标识:Senparc - 20150211 修改标识:Senparc - 20150303 修改描述:整理接口 修改标识:Senparc - 20170522 修改描述:v6.3.2 修改TenPayUtil.GetNoncestr()方法,将编码由GBK改为UTF8 ----------------------------------------------------------------*/ using System; using System.IO; using System.Net; using System.Security.Cryptography; using System.Text; namespace Senparc.Weixin.Tencent { 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; } /// /// 解密方法 /// /// 密文 /// /// /// 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)SystemTime.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) { #if NET35 || NET40 || NET45 var aes = new RijndaelManaged(); #else var aes = Aes.Create(); #endif //秘钥的大小,以位为单位 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) { #if NET35 || NET40 || NET45 var aes = new RijndaelManaged(); #else var aes = Aes.Create(); #endif //秘钥的大小,以位为单位 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) { #if NET35 || NET40 || NET45 var aes = new RijndaelManaged(); #else var aes = Aes.Create(); #endif aes.KeySize = 128;//原始: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; } } }