Направление с утечками памяти в методе шифрования AES

Может любой определить является там любыми возможными утечками памяти в следующем коде. Я попробовал.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;
    }
5
задан Mubashar 24 May 2010 в 12:59
поделиться

2 ответа

Обновление : после дополнительного расследования я зарегистрировал это как ошибку на Microsoft connect . Они признали ошибку и создали исправление . (Очевидно, что это исправление, поэтому применяются обычные заявления об отказе от ответственности. Если вы можете, обновление до .net 4.0, вероятно, было бы предпочтительным решением)


Похоже, что этот код просачивается в .net 3.5, но отлично работает в .net 4.0.

Я начал с .net 4.0 и скопировал ваш код в приложение для быстрого тестирования и вызвал его 1000000 раз, при этом использование памяти оставалось постоянным на уровне 22,4 МБ все время. Я также отслеживал размеры кучи GC и количество дескрипторов, и все они оставались неизменными. Насколько я могу судить, этот код не протекает.

Затем я перестроил приложение под .net 3.5 и повторно запустил тест, и я получил точную утечку, которую вы описываете. Он начинался с 24 Мбайт, а к тому времени, когда было совершено 100 000 вызовов, использование памяти увеличилось вдвое и превысило 50 Мбайт. Интересно, что, похоже, увеличивалась куча 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;
        }

    }
}
8
ответ дан 14 December 2019 в 04:31
поделиться

Не пытаюсь захватить тему, но в чем основная разница между вашим шифром и этим?


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

Я запустил этот под 3.5 и он не сдвинулся дальше 22мб. Мои навыки в криптографии невелики, но мне просто интересно, почему один лучше другого, и так ли это. Кажется, есть много способов делать одно и то же.

0
ответ дан 14 December 2019 в 04:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: