【发布时间】:2013-03-01 07:59:56
【问题描述】:
我对 AES 加密/解密有疑问。注释代码有效,但有时会出现错误“填充无效且无法删除”,因此我更改了它,因为这里解释了 Padding is invalid and cannot be removed Exception while decrypting string using "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 返回值之前
我希望它能帮助遇到和我一样问题的人。
【问题讨论】:
-
如果你稍微整理一下你的实现,你会更容易找到问题。
-
现在我尝试使用此处的msdn.microsoft.com/en-us/library/… 代码,这段代码给了我“填充无效”异常。因此,当我使用来自 MSDN 的示例代码时,要么我有一个空字符串,要么有时“填充无效异常”。
-
我发现来自 msdn 的代码在需要解密/加密大量数据的情况下不起作用。
-
你的代码也不能处理小数据,不知道为什么,我也看到了 Hans Passant 的评论,但它不起作用。从我看到的情况来看,您已经按照您的指示进行了接线。
-
如果你有一个新问题,你需要作为一个不同的问题发布,即“加密大数据的问题”需要在一个新问题中发布,不要随着你的进步而改变这个问题这不是这个网站应该如何运作的。
标签: c# .net cryptography aes rijndaelmanaged