using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace SiteCore.taoObj { using System.Diagnostics.CodeAnalysis; using System.Security.Cryptography; using System.Text; namespace WebApi { public class CallbackCrypto { private readonly byte[] _aesKey; private readonly string _clientId; //随机字符串字节长度 private static readonly int RANDOM_LENGTH = 16; /// /// 构造函数 /// /// 开放平台上,开发者设置的EncodingAESKey /// 开放平台上,应用的clientId /// public CallbackCrypto(string encodingAesKey, string clientId) { if (encodingAesKey == null) { throw new Exception("加密密钥不能为空"); } _clientId = clientId; _aesKey = Convert.FromBase64String(encodingAesKey); } /// /// 将和开放平台同步的消息体加密,返回加密Map /// /// 传递的消息体明文 /// public Dictionary GetEncryptedMap(string plaintext) { return GetEncryptedMap(plaintext, DateTime.Now.Millisecond); } /// /// 将和开放平台同步的消息体加密,返回加密Map /// /// 传递的消息体明文 /// 时间戳 /// /// public Dictionary GetEncryptedMap(string plaintext, long timestamp) { if (null == plaintext) { throw new Exception("加密明文字符串不能为空"); } var nonce = Utils.GetRandomStr(RANDOM_LENGTH); string encrypt = Encrypt(nonce, plaintext); string signature = GetSignature(timestamp.ToString(), nonce, encrypt); return new Dictionary() { ["signature"] = signature, ["encrypt"] = encrypt, ["timestamp"] = timestamp.ToString(), ["nonce"] = nonce }; } /// /// 密文解密 /// /// 签名串 /// 时间戳 /// 随机串 /// 密文 /// 解密后的原文 /// public string GetDecryptMsg(string msgSignature, string timestamp, string nonce, string encryptMsg) { //校验签名 string signature = GetSignature(timestamp, nonce, encryptMsg); if (!signature.Equals(msgSignature)) { throw new Exception("签名不匹配"); } // 解密 return Decrypt(encryptMsg); } /// /// 对明文加密 /// /// 随机串 /// 需要加密的明文 /// 加密后base64编码的字符串 /// private string Encrypt(string nonce, string plaintext) { byte[] randomBytes = Encoding.UTF8.GetBytes(nonce); byte[] plainTextBytes = Encoding.UTF8.GetBytes(plaintext); byte[] lengthByte = Utils.Int2Bytes(plainTextBytes.Length); byte[] clientIdBytes = Encoding.UTF8.GetBytes(_clientId); var bytestmp = new List(); bytestmp.AddRange(randomBytes); bytestmp.AddRange(lengthByte); bytestmp.AddRange(plainTextBytes); bytestmp.AddRange(clientIdBytes); byte[] padBytes = PKCS7Padding.GetPaddingBytes(bytestmp.Count); bytestmp.AddRange(padBytes); byte[] unencrypted = bytestmp.ToArray(); using (Aes aesAlg = Aes.Create()) { aesAlg.Mode = CipherMode.CBC; aesAlg.Padding = PaddingMode.Zeros; aesAlg.Key = _aesKey; aesAlg.IV = _aesKey.ToList().Take(16).ToArray(); // Create an encryptor to perform the stream transform. ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV); byte[] encrypted = encryptor.TransformFinalBlock(unencrypted, 0, unencrypted.Length); return Convert.ToBase64String(encrypted, 0, encrypted.Length); } } /// /// 对密文进行解密 /// /// 需要解密的密文 /// 解密得到的明文 /// private string Decrypt(string text) { byte[] originalArr; byte[] toEncryptArray = Convert.FromBase64String(text); using (Aes aesAlg = Aes.Create()) { aesAlg.Mode = CipherMode.CBC; aesAlg.Padding = PaddingMode.Zeros; aesAlg.Key = _aesKey; aesAlg.IV = _aesKey.ToList().Take(16).ToArray(); // Create a decryptor to perform the stream transform. ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV); // Create the streams used for decryption. originalArr = decryptor.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); } string plaintext; string msgClientId; // 去除补位字符 byte[] bytes = PKCS7Padding.RemovePaddingBytes(originalArr); int plainTextLegth = Utils.Bytes2int(bytes.Skip(RANDOM_LENGTH).Take(4).ToArray()); plaintext = Encoding.UTF8.GetString(bytes.Skip(RANDOM_LENGTH + 4).Take(plainTextLegth).ToArray()); msgClientId = Encoding.UTF8.GetString(bytes.Skip(RANDOM_LENGTH + 4 + plainTextLegth).ToArray()); return !msgClientId.Equals(_clientId) ? throw new Exception("计算解密文字clientId不匹配") : plaintext; } /// /// 生成数字签名 /// /// 时间戳 /// 随机串 /// 加密文本 /// /// public string GetSignature(string timestamp, string nonce, string encrypt) { string[] array = new string[] { _clientId, timestamp, nonce, encrypt }; Array.Sort(array, StringComparer.Ordinal); SHA1 sHA1 = SHA1.Create(); byte[] digest = sHA1.ComputeHash(Encoding.ASCII.GetBytes(string.Join(string.Empty, array))); StringBuilder hexstr = new StringBuilder(); for (int i = 0; i < digest.Length; i++) { hexstr.Append(((int)digest[i]).ToString("x2")); } return hexstr.ToString(); } } /// /// 加解密工具类 /// public class Utils { public static string GetRandomStr(int count) { string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; Random random = new Random(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < count; i++) { int number = random.Next(chars.Length); sb.Append(chars[number]); } return sb.ToString(); } /// /// int转byte数组,高位在前 /// public static byte[] Int2Bytes(int number) { return new byte[] { (byte) (number >> 24 & 0xFF), (byte) (number >> 16 & 0xFF), (byte) (number >> 8 & 0xFF), (byte) (number & 0xFF) }; } /// /// 高位在前bytes数组转int /// public static int Bytes2int(byte[] byteArr) { int count = 0; for (int i = 0; i < 4; ++i) { count <<= 8; count |= byteArr[i] & 255; } return count; } } /// /// PKCS7算法的加密填充 /// public class PKCS7Padding { private static readonly int BLOCK_SIZE = 32; /// /// 填充mode字节 /// /// public static byte[] GetPaddingBytes(int count) { int amountToPad = BLOCK_SIZE - count % BLOCK_SIZE; if (amountToPad == 0) { amountToPad = BLOCK_SIZE; } char padChr = Chr(amountToPad); string tmp = string.Empty; for (int index = 0; index < amountToPad; index++) { tmp += padChr; } return Encoding.UTF8.GetBytes(tmp); } /// /// 移除mode填充字节 /// /// public static byte[] RemovePaddingBytes(byte[] decrypted) { int pad = decrypted[decrypted.Length - 1]; if (pad < 1 || pad > BLOCK_SIZE) { pad = 0; } var output = new byte[decrypted.Length - pad]; Array.Copy(decrypted, output, decrypted.Length - pad); return output; } private static char Chr(int a) { byte target = (byte)(a & 0xFF); return (char)target; } } } }