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 解密
}
}