2022-11-09 20:48:03 +08:00
|
|
|
|
using System;
|
2021-09-18 12:08:45 +08:00
|
|
|
|
using System.Security.Cryptography;
|
|
|
|
|
|
|
|
|
|
namespace SKIT.FlurlHttpClient.Wechat.Api.Utilities
|
|
|
|
|
{
|
2024-02-04 22:52:14 +08:00
|
|
|
|
using SKIT.FlurlHttpClient.Primitives;
|
|
|
|
|
|
2022-01-21 16:57:42 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// AES 算法工具类。
|
|
|
|
|
/// </summary>
|
2021-09-18 12:08:45 +08:00
|
|
|
|
public static class AESUtility
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
2021-10-18 17:31:32 +08:00
|
|
|
|
/// 基于 CBC 模式解密数据。
|
2021-09-18 12:08:45 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="keyBytes">AES 密钥字节数组。</param>
|
|
|
|
|
/// <param name="ivBytes">加密使用的初始化向量字节数组。</param>
|
|
|
|
|
/// <param name="cipherBytes">待解密数据字节数组。</param>
|
|
|
|
|
/// <returns>解密后的数据字节数组。</returns>
|
2021-10-18 17:31:32 +08:00
|
|
|
|
public static byte[] DecryptWithCBC(byte[] keyBytes, byte[] ivBytes, byte[] cipherBytes)
|
2021-09-18 12:08:45 +08:00
|
|
|
|
{
|
2024-01-29 23:11:56 +08:00
|
|
|
|
if (keyBytes is null) throw new ArgumentNullException(nameof(keyBytes));
|
|
|
|
|
if (ivBytes is null) throw new ArgumentNullException(nameof(ivBytes));
|
|
|
|
|
if (cipherBytes is null) throw new ArgumentNullException(nameof(cipherBytes));
|
2021-09-03 14:23:54 +08:00
|
|
|
|
|
|
|
|
|
using (SymmetricAlgorithm aes = Aes.Create())
|
|
|
|
|
{
|
2021-10-18 17:31:32 +08:00
|
|
|
|
aes.Mode = CipherMode.CBC;
|
|
|
|
|
aes.Padding = PaddingMode.PKCS7;
|
2021-09-03 14:23:54 +08:00
|
|
|
|
aes.Key = keyBytes;
|
|
|
|
|
aes.IV = ivBytes;
|
|
|
|
|
|
2021-10-18 17:31:32 +08:00
|
|
|
|
using ICryptoTransform transform = aes.CreateDecryptor();
|
|
|
|
|
return transform.TransformFinalBlock(cipherBytes, 0, cipherBytes.Length);
|
2021-09-18 12:08:45 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-09 20:48:03 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 基于 CBC 模式解密数据。
|
|
|
|
|
/// </summary>
|
2024-02-04 22:52:14 +08:00
|
|
|
|
/// <param name="encodingKey">经过编码后的(通常为 Base64)AES 密钥。</param>
|
|
|
|
|
/// <param name="encodingIV">经过编码后的(通常为 Base64)初始化向量。</param>
|
|
|
|
|
/// <param name="encodingCipher">经过编码后的(通常为 Base64)待解密数据。</param>
|
|
|
|
|
/// <returns>解密后的数据。</returns>
|
|
|
|
|
public static EncodedString DecryptWithCBC(EncodedString encodingKey, EncodedString encodingIV, EncodedString encodingCipher)
|
2022-11-09 20:48:03 +08:00
|
|
|
|
{
|
2024-02-04 22:52:14 +08:00
|
|
|
|
if (encodingKey.Value is null) throw new ArgumentNullException(nameof(encodingKey));
|
|
|
|
|
if (encodingIV.Value is null) throw new ArgumentNullException(nameof(encodingIV));
|
|
|
|
|
if (encodingCipher.Value is null) throw new ArgumentNullException(nameof(encodingCipher));
|
2022-11-09 20:48:03 +08:00
|
|
|
|
|
|
|
|
|
byte[] plainBytes = DecryptWithCBC(
|
2024-02-04 22:52:14 +08:00
|
|
|
|
keyBytes: EncodedString.FromString(encodingKey, fallbackEncodingKind: EncodingKinds.Base64),
|
|
|
|
|
ivBytes: EncodedString.FromString(encodingIV, fallbackEncodingKind: EncodingKinds.Base64),
|
|
|
|
|
cipherBytes: EncodedString.FromString(encodingCipher, fallbackEncodingKind: EncodingKinds.Base64)
|
2022-11-09 20:48:03 +08:00
|
|
|
|
);
|
2024-02-04 22:52:14 +08:00
|
|
|
|
return EncodedString.ToLiteralString(plainBytes);
|
2022-11-09 20:48:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-10-19 15:09:05 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 基于 CBC 模式加密数据。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="keyBytes">AES 密钥字节数组。</param>
|
|
|
|
|
/// <param name="ivBytes">加密使用的初始化向量字节数组。</param>
|
|
|
|
|
/// <param name="plainBytes">待加密数据字节数组。</param>
|
|
|
|
|
/// <returns>加密后的数据字节数组。</returns>
|
|
|
|
|
public static byte[] EncryptWithCBC(byte[] keyBytes, byte[] ivBytes, byte[] plainBytes)
|
|
|
|
|
{
|
2024-01-29 23:11:56 +08:00
|
|
|
|
if (keyBytes is null) throw new ArgumentNullException(nameof(keyBytes));
|
|
|
|
|
if (ivBytes is null) throw new ArgumentNullException(nameof(ivBytes));
|
|
|
|
|
if (plainBytes is null) throw new ArgumentNullException(nameof(plainBytes));
|
2021-10-19 15:09:05 +08:00
|
|
|
|
|
|
|
|
|
using (SymmetricAlgorithm aes = Aes.Create())
|
|
|
|
|
{
|
|
|
|
|
aes.Mode = CipherMode.CBC;
|
|
|
|
|
aes.Padding = PaddingMode.PKCS7;
|
|
|
|
|
aes.Key = keyBytes;
|
|
|
|
|
aes.IV = ivBytes;
|
|
|
|
|
|
|
|
|
|
using ICryptoTransform transform = aes.CreateEncryptor();
|
|
|
|
|
return transform.TransformFinalBlock(plainBytes, 0, plainBytes.Length);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-18 12:08:45 +08:00
|
|
|
|
/// <summary>
|
2021-10-19 15:09:05 +08:00
|
|
|
|
/// 基于 CBC 模式加密数据。
|
|
|
|
|
/// </summary>
|
2024-02-04 22:52:14 +08:00
|
|
|
|
/// <param name="encodingKey">经过编码后的(通常为 Base64)AES 密钥。</param>
|
|
|
|
|
/// <param name="encodingIV">经过编码后的(通常为 Base64)初始化向量。</param>
|
|
|
|
|
/// <param name="plainData">待加密数据。</param>
|
|
|
|
|
/// <returns>经过 Base64 编码的加密后的数据。</returns>
|
|
|
|
|
public static EncodedString EncryptWithCBC(EncodedString encodingKey, EncodedString encodingIV, string plainData)
|
2021-10-19 15:09:05 +08:00
|
|
|
|
{
|
2024-02-04 22:52:14 +08:00
|
|
|
|
if (encodingKey.Value is null) throw new ArgumentNullException(nameof(encodingKey));
|
|
|
|
|
if (encodingIV.Value is null) throw new ArgumentNullException(nameof(encodingIV));
|
|
|
|
|
if (plainData is null) throw new ArgumentNullException(nameof(plainData));
|
2021-10-19 15:09:05 +08:00
|
|
|
|
|
|
|
|
|
byte[] plainBytes = EncryptWithCBC(
|
2024-02-04 22:52:14 +08:00
|
|
|
|
keyBytes: EncodedString.FromString(encodingKey, fallbackEncodingKind: EncodingKinds.Base64),
|
|
|
|
|
ivBytes: EncodedString.FromString(encodingIV, fallbackEncodingKind: EncodingKinds.Base64),
|
|
|
|
|
plainBytes: EncodedString.FromLiteralString(plainData)
|
2021-10-19 15:09:05 +08:00
|
|
|
|
);
|
2024-02-04 22:52:14 +08:00
|
|
|
|
return EncodedString.ToBase64String(plainBytes);
|
2021-10-19 15:09:05 +08:00
|
|
|
|
}
|
2021-09-18 12:08:45 +08:00
|
|
|
|
}
|
|
|
|
|
}
|