c# - AES加密方式面临内存泄露

标签 c# .net-3.5 memory-leaks cryptography

任何人都可以确定以下代码中是否存在任何可能的内存泄漏。我尝试过使用 .Net Memory Profiler,它说“CreateEncryptor”和一些其他函数正在留下非托管内存泄漏,因为我已经使用性能监视器确认了这一点。

但已经有处置、明确、关闭的电话,请尽可能告知我。这很紧急。

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;
    }

最佳答案

更新:经过更多调查后,我将其记录为 Microsoft connect 上的错误.他们已经确认了这个错误并创建了一个 hotfix . (显然,这是一个修补程序,因此适用通常的免责声明。如果可以,升级到 .net 4.0 可能是首选解决方案)


这段代码似乎在 .net 3.5 中泄漏,但在 .net 4.0 中运行良好。

我从 .net 4.0 开始并将您的代码复制到一个快速测试应用程序中并调用它 1,000,000 次,内存使用量始终保持在 22.4mb。我还跟踪了 GC 堆大小和句柄数,它们都保持不变。据我所知,代码没有泄漏。

然后我在 .net 3.5 下重建了应用程序并重新运行测试,我得到了你所描述的确切泄漏。它开始时大约 24mb,当它进行了 100k 次调用时,内存使用量翻了一番,超过 50mb。有趣的是,它似乎是 Gen2 堆在增加,这表明它是托管内存泄漏,而不是非托管句柄/内存。

如果可能的话,我建议您尝试切换到 .net 4.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;
        }

    }
}

关于c# - AES加密方式面临内存泄露,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2897128/

相关文章:

c# - 当文本从方法内部更改时,RichTextBox.TextChanged 事件不会触发

c# - GridView 查询不显示

cocoa - 纠正 NSView 内存泄漏

c - C的内存泄漏检测器?

c# - 真的很长的消息在套接字接收时被切断

c# - 如何配置对 YouTube 凭据进行身份验证的网站以供控制台应用程序使用?

第一次调用 CanExecute 时 WPF CommandParameter 为 NULL

c# - WCF 错误 - 安全处理器无法在消息中找到安全 header

xml - 无关的 wcf 主体 xml 命名空间声明

c++ - Dr.Memory 发现的错误 : don't know how to fix it