我对 AES 加密/解密有疑问。注释代码有效,但有时会出现错误“填充无效且无法删除”,因此我更改了它,因为它在此处解释填充无效且无法删除 使用“AesManaged”C# 解密字符串时出现异常
但是当我尝试解密时,下面的代码给出了一个空字符串。我不知道我在哪里犯错。两个静态函数 bytesToString 和 stringToBytes 与加密无关,我在其他地方使用它们。密钥长度和块大小是可以的。我在调试器中发现了这个:
“'csEncrypt.Length' 引发了类型为 'System.NotSupportedException' 的异常”
我在 3.5 .NET Visual STudio 2008 上工作
这是来自调试器的 prtscr,您可以在将块加密后看到的长度为 0 字节,并且加密流有一些例外
如何解决?请给我一些线索。
static class Aes
{
public static string bytesToHexString(byte[] key)
{
return BitConverter.ToString(key).Replace("-", String.Empty);
}
public static byte[] stringToBytes(string key)
{
return Enumerable.Range(0, key.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(key.Substring(x, 2), 16))
.ToArray();
}
public static void generateKeyAndIv(out byte[] key, out byte[] IV)
{
using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
{
aesAlg.BlockSize = 128;
aesAlg.KeySize = 256;
aesAlg.Padding = PaddingMode.None;
//aesAlg.Mode = CipherMode.CBC;
aesAlg.GenerateKey();
aesAlg.GenerateIV();
key = aesAlg.Key;
IV = aesAlg.IV;
}
}
public static string EncryptStringToString(string plainText, byte[] Key, byte[] IV)
{
byte[] bytes =EncryptStringToBytes_Aes(plainText, Key, IV);
return Convert.ToBase64String(bytes);
//return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
}
public static string DecryptStringToString(string cipherText, byte[] Key, byte[] IV)
{
//byte[] bytes = Encoding.UTF8.GetBytes(cipherText);
byte[] bytes = Convert.FromBase64String(cipherText);
return DecryptStringFromBytes_Aes(bytes, Key, IV);
}
public static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");
/*byte[] encrypted;
// Create an AesCryptoServiceProvider object
// with the specified key and IV.
using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
{
aesAlg.BlockSize = 128;
aesAlg.KeySize = 256;
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.Mode = CipherMode.CBC;
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
}
encrypted = msEncrypt.ToArray();
}
}*/
byte[] encrypted;
// Create an AesManaged object
// with the specified key and IV.
using (AesManaged aesAlg = new AesManaged())
{
// Create a decrytor to perform the stream transform.
aesAlg.Padding = PaddingMode.None;
aesAlg.BlockSize = 128;
aesAlg.KeySize = 256;
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using (var msEncrypt = new MemoryStream())
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
using (var swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
csEncrypt.FlushFinalBlock();
encrypted = msEncrypt.ToArray();
}
}
//return encrypted;
// Return the encrypted bytes from the memory stream.
return encrypted;
}
public static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
// Declare the string used to hold
// the decrypted text.
string plaintext = null;
// Create an AesCryptoServiceProvider object
// with the specified key and IV.
using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
{
aesAlg.BlockSize = 128;
aesAlg.KeySize = 256;
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.Mode = CipherMode.CBC;
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
}
好的,也许我会多解释一下整个情况。我写了自己的安全电子邮件。我有 2x 加密。服务器和客户端之间的通信使用 RSA 和 AES 加密。用户创建的消息也由 RSA + AES 加密。
发送消息如下所示:
- 客户端连接到服务器。
- 它们建立安全连接(服务器发送其公钥,客户端生成 AES 密钥通过服务器的公钥对其进行加密并将其发送到服务器。之后服务器和客户端使用 AES 密钥进行通信)。
- 客户端以 XML 格式创建消息,消息可以包含读取到 base64 并使用 AES 加密的文件。
- 消息被写入 db。
接收消息如下所示:
- 连接到服务器。
- 建立安全连接。
- 从服务器获取消息。
- 使用 RSA 私钥解密 AES 密钥。
- 使用解密的 AES 密钥解密消息。
- 如果有文件,则使用 AES 和 base64_decode 将它们解密为字节并保存。
现在的问题在于大数据的加密。即使是 200-300 kB 有时也是个问题。
我发现的另一件有趣的事情是,当我通过调试器运行代码时,它可以工作,但是当我在没有它的情况下运行代码时。它不起作用。
解决方案
我找到了问题的解决方案。因为我用不同的密钥/ivs 垃圾收集器一次又一次地非常快地使用了两次 AES 加密/解密,所以垃圾收集器没有清理这些对象。解决方案是添加
GC.Collect();
GC.WaitForPendingFinalizers();
就在 DecryptStringFromBytes_Aes 和 EncryptStringToBytes_Aes 返回值之前
我希望它能帮助像我一样遇到同样问题的人。