using Ds.Module.WeChat.Models; using Newtonsoft.Json; using System.Security.Cryptography; using System.Text; namespace Ds.Module.WeChat.Utilities { /// /// 签名及加密帮助类 /// public static class EncryptHelper { ///// ///// SHA1加密 ///// ///// ///// //public static string EncryptToSHA1(string str) //{ // SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); // byte[] str1 = Encoding.UTF8.GetBytes(str); // byte[] str2 = sha1.ComputeHash(str1); // sha1.Clear(); // (sha1 as IDisposable).Dispose(); // return Convert.ToBase64String(str2); //} #region 签名 /// /// 获得签名 /// /// /// /// public static string GetSignature(string rawData, string sessionKey) { var signature = GetSha1(rawData + sessionKey); //Senparc.Weixin.Helpers.EncryptHelper.SHA1_Encrypt(rawData + sessionKey); return signature; } /// 采用SHA-1算法加密字符串(小写) /// 需要加密的字符串 /// public static string GetSha1(string encypStr) { byte[] hash = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(encypStr)); StringBuilder stringBuilder = new StringBuilder(); foreach (byte num in hash) stringBuilder.AppendFormat("{0:x2}", (object)num); return stringBuilder.ToString(); } /// /// 比较签名是否正确 /// /// /// /// /// 当SessionId或SessionKey无效时抛出异常 /// public static bool CheckSignature(string sessionKey, string rawData, string compareSignature) { var signature = GetSignature(rawData, sessionKey); return signature == compareSignature; } #endregion 签名 #region 解密 #region 私有方法 private static byte[] AES_Decrypt(String Input, byte[] Iv, byte[] Key) { #if NET45 RijndaelManaged aes = new RijndaelManaged(); #else SymmetricAlgorithm aes = Aes.Create(); #endif aes.KeySize = 128;//原始:256 aes.BlockSize = 128; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; aes.Key = Key; aes.IV = Iv; var decrypt = aes.CreateDecryptor(aes.Key, aes.IV); byte[] xBuff = null; //using (ICryptoTransform decrypt = aes.CreateDecryptor(aes.Key, aes.IV) /*aes.CreateDecryptor()*/) //{ // var src = Convert.FromBase64String(Input); // byte[] dest = decrypt.TransformFinalBlock(src, 0, src.Length); // return dest; // //return Encoding.UTF8.GetString(dest); //} try { using (var ms = new MemoryStream()) { using (var cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Write)) { //cs.Read(decryptBytes, 0, decryptBytes.Length); //cs.Close(); //ms.Close(); //cs.FlushFinalBlock();//用于解决第二次获取小程序Session解密出错的情况 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); } //cs.Dispose(); xBuff = decode2(ms.ToArray()); } } catch (System.Security.Cryptography.CryptographicException) { //Padding is invalid and cannot be removed. Console.WriteLine("===== CryptographicException ====="); using (var ms = new MemoryStream()) { //cs 不自动释放,用于避免“Padding is invalid and cannot be removed”的错误 —— 2019.07.27 Jeffrey var cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Write); { //cs.Read(decryptBytes, 0, decryptBytes.Length); //cs.Close(); //ms.Close(); //cs.FlushFinalBlock();//用于解决第二次获取小程序Session解密出错的情况 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); } //cs.Dispose(); 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; } #endregion 私有方法 /// /// 解密所有消息的基础方法 /// /// 储存在 SessionBag 中的当前用户 会话 SessionKey /// 接口返回数据中的 encryptedData 参数 /// 接口返回数据中的 iv 参数,对称解密算法初始向量 /// public static string DecodeEncryptedData(string sessionKey, string encryptedData, string iv) { //var aesCipher = Convert.FromBase64String(encryptedData); var aesKey = Convert.FromBase64String(sessionKey); var aesIV = Convert.FromBase64String(iv); var result = AES_Decrypt(encryptedData, aesIV, aesKey); var resultStr = Encoding.UTF8.GetString(result); return resultStr; } /// /// 解密消息(通过SessionId获取) /// /// /// /// /// 当SessionId或SessionKey无效时抛出异常 /// public static string DecodeEncryptedDataBySessionId(string sessionKey, string encryptedData, string iv) { var resultStr = DecodeEncryptedData(sessionKey, encryptedData, iv); return resultStr; } /// /// 检查解密消息水印 /// /// /// /// entity为null时也会返回false public static bool CheckWatermark(this DecodeEntityBase entity, string appId) { if (entity == null) { return false; } return //entity.watermark.appid ==APPID true; } #region 解密实例信息 /// /// 解密到实例信息 /// /// DecodeEntityBase /// /// /// /// public static T DecodeEncryptedDataToEntity(string sessionKey, string encryptedData, string iv) { var jsonStr = DecodeEncryptedDataBySessionId(sessionKey, encryptedData, iv); //Console.WriteLine("===== jsonStr ====="); //Console.WriteLine(jsonStr); //Console.WriteLine(); var entity = JsonConvert.DeserializeObject(jsonStr); return entity; } /// /// 解密到实例信息 /// /// DecodeEntityBase /// /// /// /// public static T DecodeEncryptedDataToEntityEasy(string sessionKey, string encryptedData, string iv) { var jsonStr = DecodeEncryptedData(sessionKey, encryptedData, iv); var entity = JsonConvert.DeserializeObject(jsonStr); return entity; } /// /// 解密UserInfo消息(通过SessionId获取) /// /// /// /// /// 当SessionId或SessionKey无效时抛出异常 /// public static DecodedUserInfo DecodeUserInfoBySessionId(string sessionKey, string encryptedData, string iv) { return DecodeEncryptedDataToEntity(sessionKey, encryptedData, iv); } /// /// 解密手机号 /// /// /// /// /// public static DecodedPhoneNumber DecryptPhoneNumber(string sessionKey, string encryptedData, string iv) { return DecodeEncryptedDataToEntity(sessionKey, encryptedData, iv); } /// /// 解密手机号(根据sessionKey解密) /// /// /// /// /// public static DecodedPhoneNumber DecryptPhoneNumberBySessionKey(string sessionKey, string encryptedData, string iv) { //var resultStr = DecodeEncryptedData(sessionKey, encryptedData, iv); //var entity = SerializerHelper.GetObject(resultStr); //return entity; return DecodeEncryptedDataToEntityEasy(sessionKey, encryptedData, iv); } /// /// 解密微信小程序运动步数 /// 2019-04-02 /// /// /// /// /// public static DecodedRunData DecryptRunData(string sessionId, string encryptedData, string iv) { return DecodeEncryptedDataToEntity(sessionId, encryptedData, iv); } #endregion 解密实例信息 #endregion 解密 } }