在 .NET Core 和 .NET Framework 中使用 AES 进行加密和解密
阅读:81
点赞:0
一. 介绍
AES(高级加密标准)是一种对称密钥算法,这意味着加密和解密使用相同的密钥。与非对称加密(使用公钥进行加密和私钥进行解密)不同,AES 在处理数据时,保持了密钥的一致性。
二. 加密过程
1. 设置 RijndaelManaged 对象
using (var rijndaelManaged = new RijndaelManaged
{
Key = cryptkey,
IV = initVector,
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7,
KeySize = 128
})
-
RijndaelManaged: .NET 框架中用于执行 AES 加密的类。 -
Key: 加密密钥。必须是 128、192 或 256 位(16、24 或 32 字节)长。 -
IV: 初始化向量,用于为加密过程添加随机性。 -
Mode = CipherMode.CBC: 设置为密码块链模式(CBC)。在加密前,每块明文会与前一个密文块进行异或操作。 -
Padding = PaddingMode.PKCS7: 指定填充方案,以确保数据长度与密码块大小兼容。 -
KeySize = 128: 加密密钥的大小,以位为单位(这里是 128 位)。
2. 使用 MemoryStream
using (var memoryStream = new MemoryStream())
-
MemoryStream: 内存中的流,用于写入加密后的字节。
3. 创建 CryptoStream
using (var cryptoStream = new CryptoStream(memoryStream,
rijndaelManaged.CreateEncryptor(cryptkey, initVector),
CryptoStreamMode.Write))
-
CryptoStream: 将数据流链接到加密变换。这里它包裹了 MemoryStream。 -
CreateEncryptor(cryptkey, initVector): 使用提供的密钥和 IV 创建对称加密器对象。 -
CryptoStreamMode.Write: 指定该流将用于写入操作。
4. 写入数据
using (var ws = new StreamWriter(cryptoStream))
{
ws.Write(textToCrypt);
}
-
StreamWriter: 用于向流中写入字符。它将明文 textToCrypt
写入 CryptoStream,CryptoStream 会自动加密,并将结果写入 MemoryStream。
5. 返回加密结果
return Convert.ToBase64String(memoryStream.ToArray());
-
Convert.ToBase64String: 将存储在 MemoryStream 中的加密字节转换为 Base64 字符串,并作为加密结果返回。
完整的加密方法
public string EncryptAES(string textToCrypt)
{
private byte[] cryptkey = Encoding.ASCII.GetBytes("1234567891234567");
private byte[] initVector = Encoding.ASCII.GetBytes("1234567891234567");
try
{
using (var rijndaelManaged =
new RijndaelManaged { Key = cryptkey, IV = initVector, Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7, KeySize = 128 })
using (var memoryStream = new MemoryStream())
using (var cryptoStream =
new CryptoStream(memoryStream,
rijndaelManaged.CreateEncryptor(cryptkey, initVector),
CryptoStreamMode.Write))
{
using (var ws = new StreamWriter(cryptoStream))
{
ws.Write(textToCrypt);
}
return Convert.ToBase64String(memoryStream.ToArray());
}
}
catch (CryptographicException e)
{
Console.WriteLine("发生加密错误: {0}", e.Message);
return null;
}
}
运行结果
三. 解密过程
完整的解密方法
public string DecryptAES(string cipherData)
{
try
{
using (var rijndaelManaged =
new RijndaelManaged { Key = cryptkey, IV = initVector, Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7, KeySize = 128 })
using (var memoryStream =
new MemoryStream(Convert.FromBase64String(cipherData)))
using (var cryptoStream =
new CryptoStream(memoryStream,
rijndaelManaged.CreateDecryptor(cryptkey, initVector),
CryptoStreamMode.Read))
{
return new StreamReader(cryptoStream).ReadToEnd();
}
}
catch (CryptographicException e)
{
Console.WriteLine("发生解密错误: {0}", e.Message);
return null;
}
}
解密示例输出
通过 DecryptAES
方法可以将加密的 Base64 字符串转换回原始文本。
四. AES 的不同选项
密钥大小
-
192 位: 可使用 KeySize = 192
以提高安全性。 -
256 位: KeySize = 256
提供最高级别的安全性,但可能会影响性能。 -
128 位: 默认密钥大小为 128 位。
填充模式
-
PaddingMode.None: 不添加填充。需确保明文长度是块大小的倍数。 -
PaddingMode.Zeros: 使用零填充,但如果明文以零字节结尾,可能在解密时造成歧义。 -
PaddingMode.ANSIX923: 用零填充,并添加一个字节表示填充字节的数量。 -
PaddingMode.ISO10126: 用随机字节填充,并添加一个字节表示填充字节的数量。 -
PaddingMode.PKCS7: 使用填充以使明文成为块大小的倍数。PKCS7 是常见的填充方案,它在明文末尾追加字节,每个字节的值表示添加的填充字节数。
模式
-
CipherMode.ECB: 电子密码本模式(ECB),每个明文块独立加密。这种模式安全性较差,因为相同的明文块会产生相同的密文块。 -
CipherMode.CFB: 密码反馈模式(CFB),将块密码转化为流密码,允许以更小的块加密数据。 -
CipherMode.OFB: 输出反馈模式(OFB),同样将块密码转化为流密码,避免错误传播。 -
CipherMode.CTS: 密文偷取模式(CTS),处理不是块大小倍数的明文数据而不需要填充。 -
CipherMode.CBC: 密码块链接模式(CBC),每个明文块与前一个密文块进行异或后加密,是常见的块密码模式。
五. 结论
在 AES 加密过程中,你可以定义加密密钥、初始化向量(IV)、密码模式、填充模式和密钥大小。这些选项在确定加密过程的安全性和行为方面起着关键作用。根据具体的安全需求,可以定制这些设置,平衡安全强度、性能和兼容性。