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;
}
}
}
}