C# AES加密方法中的内存泄漏问题
请任何人确认以下代码中是否存在任何可能的内存泄漏。我曾尝试使用.Net内存探查器,它显示“CreateEncryptor”和其他一些函数正在留下非托管内存泄漏,因为我已使用性能监视器确认了这一点 但已经有处理,清除,关闭电话放置在任何可能的地方,请相应地通知我。这是一个紧急的问题C# AES加密方法中的内存泄漏问题,c#,.net-3.5,memory-leaks,cryptography,C#,.net 3.5,Memory Leaks,Cryptography,请任何人确认以下代码中是否存在任何可能的内存泄漏。我曾尝试使用.Net内存探查器,它显示“CreateEncryptor”和其他一些函数正在留下非托管内存泄漏,因为我已使用性能监视器确认了这一点 但已经有处理,清除,关闭电话放置在任何可能的地方,请相应地通知我。这是一个紧急的问题 public static string Encrypt(string plainText, string key) { //Set up the encryption objects
public static string Encrypt(string plainText, string key)
{
//Set up the encryption objects
byte[] encryptedBytes = null;
using (AesCryptoServiceProvider acsp = GetProvider(Encoding.UTF8.GetBytes(key)))
{
byte[] sourceBytes = Encoding.UTF8.GetBytes(plainText);
using (ICryptoTransform ictE = acsp.CreateEncryptor())
{
//Set up stream to contain the encryption
using (MemoryStream msS = new MemoryStream())
{
//Perform the encrpytion, storing output into the stream
using (CryptoStream csS = new CryptoStream(msS, ictE, CryptoStreamMode.Write))
{
csS.Write(sourceBytes, 0, sourceBytes.Length);
csS.FlushFinalBlock();
//sourceBytes are now encrypted as an array of secure bytes
encryptedBytes = msS.ToArray(); //.ToArray() is important, don't mess with the buffer
csS.Close();
}
msS.Close();
}
}
acsp.Clear();
}
//return the encrypted bytes as a BASE64 encoded string
return Convert.ToBase64String(encryptedBytes);
}
private static AesCryptoServiceProvider GetProvider(byte[] key)
{
AesCryptoServiceProvider result = new AesCryptoServiceProvider();
result.BlockSize = 128;
result.KeySize = 256;
result.Mode = CipherMode.CBC;
result.Padding = PaddingMode.PKCS7;
result.GenerateIV();
result.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
byte[] RealKey = GetKey(key, result);
result.Key = RealKey;
// result.IV = RealKey;
return result;
}
private static byte[] GetKey(byte[] suggestedKey, SymmetricAlgorithm p)
{
byte[] kRaw = suggestedKey;
List<byte> kList = new List<byte>();
for (int i = 0; i < p.LegalKeySizes[0].MaxSize; i += 8)
{
kList.Add(kRaw[(i / 8) % kRaw.Length]);
}
byte[] k = kList.ToArray();
return k;
}
公共静态字符串加密(字符串明文、字符串密钥)
{
//设置加密对象
字节[]encryptedBytes=null;
使用(AESCryptServiceProvider acsp=GetProvider(Encoding.UTF8.GetBytes(key)))
{
byte[]sourceBytes=Encoding.UTF8.GetBytes(纯文本);
使用(ICryptoTransform ictE=acsp.CreateEncryptor())
{
//设置流以包含加密
使用(MemoryStream msS=新MemoryStream())
{
//执行加密,将输出存储到流中
使用(CryptoStream csS=新的CryptoStream(msS、ictE、CryptoStreamMode.Write))
{
Write(sourceBytes,0,sourceBytes.Length);
FlushFinalBlock();
//sourceBytes现在作为安全字节数组进行加密
encryptedBytes=msS.ToArray();//.ToArray()很重要,不要弄乱缓冲区
csS.Close();
}
msS.Close();
}
}
acsp.Clear();
}
//将加密字节作为BASE64编码字符串返回
返回Convert.tobase64字符串(encryptedBytes);
}
私有静态加密服务提供程序GetProvider(字节[]密钥)
{
AESCryptServiceProvider结果=新的AESCryptServiceProvider();
result.BlockSize=128;
result.KeySize=256;
结果.Mode=CipherMode.CBC;
result.Padding=PaddingMode.PKCS7;
result.GenerateIV();
result.IV=新字节[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
字节[]RealKey=GetKey(key,result);
result.Key=RealKey;
//result.IV=RealKey;
返回结果;
}
私有静态字节[]GetKey(字节[]suggestedKey,对称算法p)
{
字节[]kRaw=建议的密钥;
List kList=新列表();
对于(int i=0;i
更新:经过进一步调查后,我将此记录为一个bug。他们已经确认了这个错误,并创建了一个新的。(显然,这是一个修补程序,因此通常的免责声明适用。如果可以,升级到.net 4.0可能是首选解决方案)
这段代码似乎在.NET3.5中泄漏,但在.NET4.0中运行良好 我从.NET4.0开始,将您的代码复制到一个快速测试应用程序中,并调用了1000000次,整个过程中内存使用量始终保持在22.4mb。我还跟踪了GC堆大小和句柄计数,它们都保持不变。据我所知,代码没有泄漏 然后,我在.NET3.5下重建了应用程序并重新运行了测试,我得到了您描述的确切漏洞。它的初始容量约为24mb,到它拨打10万次电话时,内存使用量已经翻了一番,超过了50mb。有趣的是,Gen2堆似乎在增加,这表明它是托管内存泄漏,而不是非托管句柄/内存 如果可能的话,我建议您尝试切换到.NET4.0 我的完整代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.IO;
namespace ConsoleApplication5
{
class Program
{
static void Main(string[] args)
{
String encryptedString;
for (int j = 0; j < 1000; j++)
{
for (int i = 0; i < 1000; i++)
{
encryptedString = Encrypt(String.Format("test string {0} {1}", j, i), "key");
}
Console.WriteLine("j = {0}", j);
}
Console.WriteLine("Finished");
Console.ReadLine();
}
public static string Encrypt(string plainText, string key)
{
//Set up the encryption objects
byte[] encryptedBytes = null;
using (AesCryptoServiceProvider acsp = GetProvider(Encoding.UTF8.GetBytes(key)))
{
byte[] sourceBytes = Encoding.UTF8.GetBytes(plainText);
using (ICryptoTransform ictE = acsp.CreateEncryptor())
{
//Set up stream to contain the encryption
using (MemoryStream msS = new MemoryStream())
{
//Perform the encrpytion, storing output into the stream
using (CryptoStream csS = new CryptoStream(msS, ictE, CryptoStreamMode.Write))
{
csS.Write(sourceBytes, 0, sourceBytes.Length);
csS.FlushFinalBlock();
//sourceBytes are now encrypted as an array of secure bytes
encryptedBytes = msS.ToArray(); //.ToArray() is important, don't mess with the buffer
csS.Close();
}
msS.Close();
}
}
acsp.Clear();
}
//return the encrypted bytes as a BASE64 encoded string
return Convert.ToBase64String(encryptedBytes);
}
private static AesCryptoServiceProvider GetProvider(byte[] key)
{
AesCryptoServiceProvider result = new AesCryptoServiceProvider();
result.BlockSize = 128;
result.KeySize = 256;
result.Mode = CipherMode.CBC;
result.Padding = PaddingMode.PKCS7;
result.GenerateIV();
result.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
byte[] RealKey = GetKey(key, result);
result.Key = RealKey;
// result.IV = RealKey;
return result;
}
private static byte[] GetKey(byte[] suggestedKey, SymmetricAlgorithm p)
{
byte[] kRaw = suggestedKey;
List<byte> kList = new List<byte>();
for (int i = 0; i < p.LegalKeySizes[0].MaxSize; i += 8)
{
kList.Add(kRaw[(i / 8) % kRaw.Length]);
}
byte[] k = kList.ToArray();
return k;
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Security.Cryptography;
使用System.IO;
命名空间控制台应用程序5
{
班级计划
{
静态void Main(字符串[]参数)
{
字符串加密字符串;
对于(int j=0;j<1000;j++)
{
对于(int i=0;i<1000;i++)
{
encryptedString=Encrypt(String.Format(“测试字符串{0}{1}”,j,i),“密钥”);
}
WriteLine(“j={0}”,j);
}
控制台。写入线(“完成”);
Console.ReadLine();
}
公共静态字符串加密(字符串明文、字符串密钥)
{
//设置加密对象
字节[]encryptedBytes=null;
使用(AESCryptServiceProvider acsp=GetProvider(Encoding.UTF8.GetBytes(key)))
{
byte[]sourceBytes=Encoding.UTF8.GetBytes(纯文本);
使用(ICryptoTransform ictE=acsp.CreateEncryptor())
{
//设置流以包含加密
使用(MemoryStream msS=新MemoryStream())
{
//执行加密,将输出存储到流中
使用(CryptoStream csS=新的CryptoStream(msS、ictE、CryptoStreamMode.Write))
{
Write(sourceBytes,0,sourceBytes.Length);
FlushFinalBlock();
//sourceBytes现在作为安全字节数组进行加密
encryptedBytes=msS.ToArray();//.ToArray()很重要,不要弄乱缓冲区
csS.Close();
}
msS.Close();
}
}
acsp.Clear();
}
//将加密字节作为BASE64编码字符串返回
返回Convert.tobase64字符串(encryptedBytes);
}
私有静态加密服务提供程序GetProvider(字节[]密钥)
{
Ae
///
/// Encrypts a string
///
/// Text to be encrypted
/// Password to encrypt with
/// Salt to encrypt with
/// Can be either SHA1 or MD5
/// Number of iterations to do
/// Needs to be 16 ASCII characters long
/// Can be 128, 192, or 256
/// An encrypted string
public static string Encrypt(string PlainText, string Password,
string Salt, string HashAlgorithm,
int PasswordIterations, string InitialVector,
int KeySize)
{
try
{
if (string.IsNullOrEmpty(PlainText))
return "";
byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector);
byte[] SaltValueBytes = Encoding.ASCII.GetBytes(Salt);
byte[] PlainTextBytes = Encoding.UTF8.GetBytes(PlainText);
PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(Password, SaltValueBytes, HashAlgorithm, PasswordIterations);
byte[] KeyBytes = DerivedPassword.GetBytes(KeySize / 8);
RijndaelManaged SymmetricKey = new RijndaelManaged();
SymmetricKey.Mode = CipherMode.CBC;
byte[] CipherTextBytes = null;
using (ICryptoTransform Encryptor = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes))
{
using (MemoryStream MemStream = new MemoryStream())
{
using (CryptoStream CryptoStream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write))
{
CryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length);
CryptoStream.FlushFinalBlock();
CipherTextBytes = MemStream.ToArray();
MemStream.Close();
CryptoStream.Close();
CryptoStream.Dispose();
MemStream.Dispose();
}
}
Encryptor.Dispose();
}
SymmetricKey.Clear();
return Convert.ToBase64String(CipherTextBytes);
}
catch { throw; }
}