Почему я не могу совместить шифрование с файловым хранилищем, когда они работают индивидуально? - PullRequest
1 голос
/ 23 февраля 2011

Я довольно новичок в C #, поэтому, пожалуйста, прости меня за это.Я очень долго бился головой об стену, и не могу найти решение.Вероятно, это что-то очень очевидное.

Итак, вот оно: я записываю некоторые свойства объекта в файл.Сначала я конвертирую свойства в байтовый массив, а затем собираю весь массив (для «одного объекта») и шифрую его через MemoryStream с использованием Aes.Я знаю о сериализации и других возможностях, но мне действительно нужно сделать это таким образом.В каком-то другом методе я читаю этот файл кусками («объектами»), дешифрую его и затем восстанавливаю свойства объекта из байтового массива.Дело в том, что только самая первая запись («объект») дешифруется и восстанавливается нормально / правильно.Все остальные получают испорченные данные (int получает значение 48464 вместо 2, String показывает нечетные знаки, double это -3.16 ... E-161 вместо 20 ...).

И я понятия не имею, почему,Я перепробовал все, что мог придумать.Если я закомментирую шифрование и дешифрование, все работает, так что это не проблема с записью и чтением.Если я размещаю код для дешифрования и восстановления объектов чуть ниже кода для шифрования (чтобы я расшифровывал записываемый фрагмент данных), он дешифрует и восстанавливает все должным образом, поэтому проблем с дешифрованием и реконструкцией быть не должно.Но когда это все вместе, это просто портит.Я действительно потерян здесь.

Пожалуйста, не сосредотачивайтесь на том, как я манипулирую данными, сейчас это действительно не важно, и у меня есть свои причины, почему я делаю это таким образом.

Вот весь код для сохранения в файл:

//constant for setting inUse
        byte setInUse = 0x80; //1000 0000

        //constant for adding spaces to name (string)
        byte[] space = Encoding.UTF8.GetBytes(" ");

        //result
        byte[] data = new byte[32];

        //setup encryption (AES)
        SymmetricAlgorithm aes = Aes.Create();
        byte[] key = { 145, 12, 32, 245, 98, 132, 98, 214, 6, 77, 131, 44, 221, 3, 9, 50 };
        byte[] iv = { 15, 122, 132, 5, 93, 198, 44, 31, 9, 39, 241, 49, 250, 188, 80, 7 };
        aes.Padding = PaddingMode.None;
        ICryptoTransform encryptor = aes.CreateEncryptor(key, iv);        

        //setup file stream for saving data
        FileStream fStream = new FileStream(file, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read, 1024, false);
        if(writeIndex != 0)
            fStream.Position = writeIndex +1;

        fStream.Position = 0; //delete me

        foreach(Article article in articles)
        {
           if(article.MyIsNew)
           {
               article.MyInUseChanged = false;
               article.MyPriceChanged = false;

               //convert article to byte array
               //id
               byte[] id = BitConverter.GetBytes(Convert.ToUInt16(article.MyId));   
               //in use
               if (article.MyInUse)
                   id[0] = (byte)( id[0] | setInUse);

               data[0] = id[0];
               data[1] = id[1];

               //stock
               byte[] stock = BitConverter.GetBytes(article.MyStock);
               data[2] = stock[0];
               data[3] = stock[1];
               data[4] = stock[2];
               data[5] = stock[3];
               data[6] = stock[4];
               data[7] = stock[5];
               data[8] = stock[6];
               data[9] = stock[7];

               //name
               byte[] name = Encoding.UTF8.GetBytes(article.MyName);
               int counter = 10;
               for (int i = 0; i < name.Length; i++)
               {
                   data[counter] = name[i];
                   counter++;
               }

               //adding spaces
               int numToAdd = 22-name.Length;
               for (int i = 0; i < numToAdd; i++)
               {
                   data[counter] = space[0];
               }

               //encrypt
               MemoryStream m = new MemoryStream();
               using (Stream c = new CryptoStream(m, encryptor, CryptoStreamMode.Write))
                   c.Write(data, 0, data.Length);
               byte[] original = new byte[32];
               original = m.ToArray();
               fStream.Write(original, 0, original.Length);

           }
           else if (article.MyInUseChanged)
           {

           }

           if (article.MyPriceChanged)
           {

           }

        }   
        fStream.Flush();
        fStream.Close();
        fStream.Dispose();

А вот весь код для загрузки:

String fileName = path + "\\articles";

        //load data
        if (File.Exists(fileName))
        {
            FileStream fStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, false);

            //setup encryption (AES)
            SymmetricAlgorithm aes = Aes.Create();
            byte[] key = { 145, 12, 32, 245, 98, 132, 98, 214, 6, 77, 131, 44, 221, 3, 9, 50 };
            byte[] iv = { 15, 122, 132, 5, 93, 198, 44, 31, 9, 39, 241, 49, 250, 188, 80, 7 };
            aes.Padding = PaddingMode.None;
            ICryptoTransform decryptor = aes.CreateDecryptor(key, iv);

            //constant for extracting inUse
            byte inUseConst = 0x80;

            //constant for extracting id
            byte idConst = 0x7F;

            byte[] idArray = new byte[2];

            //reading & constructing & adding articles to the list
            int numBytesToRead = (int)fStream.Length;
            while (numBytesToRead > 0)
            {
                byte[] original = new byte[32];
                byte[] data = new byte[32];

                int len = fStream.Read(original, 0, 32);
                numBytesToRead -= 32;
                if (len == 0 || len != 32)
                {
                    MessageBox.Show("Error while loading articles");
                    break;
                }
                long pos = fStream.Position; //delete me
                //decrypt
                MemoryStream m = new MemoryStream();
                using (Stream c = new CryptoStream(m, decryptor, CryptoStreamMode.Write))
                    c.Write(original, 0, original.Length);
                data = m.ToArray();

                //constructing object - article
                //inUse
                byte inUseCalc = (byte)(data[0] & inUseConst);
                bool inUse = false;
                if (inUseCalc != 0)
                {
                    inUse = true;
                }

                //id
                data[0] = (byte)(data[0] & idConst);
                int id = (int)(BitConverter.ToUInt16(data, 0));

                //stock
                double stock = BitConverter.ToDouble(data, 2);

                //name
                String name = Encoding.UTF8.GetString(data, 10, 22);

                Article article = new Article(id, 10, name, inUse, stock);
                articles.Add(article);

Некоторые вещи не оптимальны, потому что я сильно изменился только дляпопытаться найти решение.Некоторые вещи (например, преобразование в uInt16 и использование «или» и т. Д.) Частично связаны со сжатием.

Пожалуйста, помогите мне решить эту проблему, и снова, пожалуйста, не сосредотачивайтесь на том, как я обращаюсь с данными или советую мне использоватьСериализация, двоичная запись или что-то подобное, у меня действительно есть свои причины.

Я действительно рассчитываю на вас, потому что у меня совершенно нет идей.Спасибо всем за ваше драгоценное время и ответы.

Ответы [ 2 ]

2 голосов
/ 23 февраля 2011

Фактическая проблема заключается в том, что вы каждый раз заново создаете вывод CryptoStream. По-видимому, это приводит к изменению некоторого состояния в шифраторе, что приводит к тому, что первые несколько байтов каждой записи выводятся иначе, чем ожидалось от расшифровщика.

Если вы создадите шифрование CryptoStream за пределами цикла, либо записав непосредственно в выходной файл или в один MemoryStream, проблема исчезнет (и я действительно проверил это на этот раз. ..)

using (var fStream = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read))
using (var m = new MemoryStream())
using (var c = new CryptoStream(m, encryptor, CryptoStreamMode.Write))
{
    foreach (Article article in articles)
    {
        // ...
        c.Write(data, 0, data.Length);
        byte[] original = new byte[32];
        original = m.ToArray();
        m.Position = 0;
        fStream.Write(original, 0, original.Length);
    }
}
0 голосов
/ 23 февраля 2011

CryptoStream используется идентично любому другому потоку, то есть, если вы оберните его вокруг FileStream и приведете его к Stream, вы не сможете заметить разницу.

В своем коде дешифрования вы пишете в CryptoStream, а не читаете из него. Вы, вероятно, хотите что-то похожее на это:

using (Stream c = new CryptoStream(fStream, decryptor, CryptoStreamMode.Read))
{
    while (numBytesToRead > 0)
    {
        byte[] original = new byte[32];
        byte[] data = new byte[32];

        int len = c.Read(original, 0, 32);
        numBytesToRead -= 32;

        // and so on
    }
}

(В соответствии с просьбой, я не передаю комментарий к вашему общему подходу. Однако я бы посоветовал вам по возможности прочитать все CryptoStream в память (записать его немедленно в MemoryStream) и закрыть исходный файл и поток объектов как можно скорее.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...