Расшифровка файла .NET - Плохие данные - PullRequest
2 голосов
/ 05 января 2010

Я переписываю старое приложение. Старое приложение сохраняло данные в файле табло, который был зашифрован с помощью следующего кода:

private const String SSecretKey = @"?B?n?Mj?";
public DataTable GetScoreboardFromFile()
{
    FileInfo f = new FileInfo(scoreBoardLocation);
    if (!f.Exists)
    {
        return setupNewScoreBoard();
    }

    DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
    //A 64 bit key and IV is required for this provider.
    //Set secret key For DES algorithm.
    DES.Key = ASCIIEncoding.ASCII.GetBytes(SSecretKey);
    //Set initialization vector.
    DES.IV = ASCIIEncoding.ASCII.GetBytes(SSecretKey);

    //Create a file stream to read the encrypted file back.
    FileStream fsread = new FileStream(scoreBoardLocation, FileMode.Open, FileAccess.Read);
    //Create a DES decryptor from the DES instance.
    ICryptoTransform desdecrypt = DES.CreateDecryptor();
    //Create crypto stream set to read and do a 
    //DES decryption transform on incoming bytes.
    CryptoStream cryptostreamDecr = new CryptoStream(fsread, desdecrypt, CryptoStreamMode.Read);

    DataTable dTable = new DataTable("scoreboard");
    dTable.ReadXml(new StreamReader(cryptostreamDecr));

    cryptostreamDecr.Close();
    fsread.Close();

    return dTable;
}

Это отлично работает. Я скопировал код в свое новое приложение, чтобы я мог создать устаревший загрузчик и преобразовать данные в новый формат. Проблема в том, что я получаю ошибку «Bad Data»:

System.Security.Cryptography.CryptographicException не было обработано Сообщение = "Плохие данные. \ R \ n" Источник = "mscorlib"

Ошибка появляется в этой строке:

dTable.ReadXml(new StreamReader(cryptostreamDecr));

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

У кого-нибудь есть идеи относительно:

А) Уметь объяснить, почему это не работает? Б) Предложите решение, которое позволило бы мне иметь возможность открывать файлы, созданные с помощью унаследованного приложения, и конвертировать их, пожалуйста?

Вот весь класс, который занимается загрузкой и сохранением табло:

using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.IO;
using System.Data;
using System.Xml;
using System.Threading;

namespace JawBreaker
{
[Serializable]
class ScoreBoardLoader
{
    private Jawbreaker jawbreaker;
    private String sSecretKey = @"?B?n?Mj?";
    private String scoreBoardFileLocation = "";
    private bool keepScoreBoardUpdated = true;
    private int intTimer = 180000;

    public ScoreBoardLoader(Jawbreaker jawbreaker, String scoreBoardFileLocation)
    {
        this.jawbreaker = jawbreaker;
        this.scoreBoardFileLocation = scoreBoardFileLocation;
    }

    //  Call this function to remove the key from memory after use for security
    [System.Runtime.InteropServices.DllImport("KERNEL32.DLL", EntryPoint = "RtlZeroMemory")]
    public static extern bool ZeroMemory(IntPtr Destination, int Length);

    // Function to Generate a 64 bits Key.
    private string GenerateKey()
    {
        // Create an instance of Symetric Algorithm. Key and IV is generated automatically.
        DESCryptoServiceProvider desCrypto = (DESCryptoServiceProvider)DESCryptoServiceProvider.Create();

        // Use the Automatically generated key for Encryption. 
        return ASCIIEncoding.ASCII.GetString(desCrypto.Key);
    }

    public void writeScoreboardToFile()
    {
        DataTable tempScoreBoard = getScoreboardFromFile();
        //add in the new scores to the end of the file.
        for (int i = 0; i < jawbreaker.Scoreboard.Rows.Count; i++)
        {
            DataRow row = tempScoreBoard.NewRow();
            row.ItemArray = jawbreaker.Scoreboard.Rows[i].ItemArray;
            tempScoreBoard.Rows.Add(row);
        }

        //before it is written back to the file make sure we update the sync info
        if (jawbreaker.SyncScoreboard)
        {
            //connect to webservice, login and update all the scores that have not been synced.

            for (int i = 0; i < tempScoreBoard.Rows.Count; i++)
            {
                try
                {
                    //check to see if that row has been synced to the server
                    if (!Boolean.Parse(tempScoreBoard.Rows[i].ItemArray[7].ToString()))
                    {
                        //sync info to server

                        //update the row to say that it has been updated
                        object[] tempArray = tempScoreBoard.Rows[i].ItemArray;
                        tempArray[7] = true;
                        tempScoreBoard.Rows[i].ItemArray = tempArray;
                        tempScoreBoard.AcceptChanges();
                    }
                }
                catch (Exception ex)
                {
                    jawbreaker.writeErrorToLog("ERROR OCCURED DURING SYNC TO SERVER UPDATE: " + ex.Message);
                }
            }
        }

        FileStream fsEncrypted = new FileStream(scoreBoardFileLocation, FileMode.Create, FileAccess.Write);
        DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
        DES.Key = ASCIIEncoding.ASCII.GetBytes(sSecretKey);
        DES.IV = ASCIIEncoding.ASCII.GetBytes(sSecretKey);
        ICryptoTransform desencrypt = DES.CreateEncryptor();
        CryptoStream cryptostream = new CryptoStream(fsEncrypted, desencrypt, CryptoStreamMode.Write);

        MemoryStream ms = new MemoryStream();
        tempScoreBoard.WriteXml(ms, XmlWriteMode.WriteSchema);

        ms.Position = 0;

        byte[] bitarray = new byte[ms.Length];
        ms.Read(bitarray, 0, bitarray.Length);

        cryptostream.Write(bitarray, 0, bitarray.Length);
        cryptostream.Close();
        ms.Close();

        //now the scores have been added to the file remove them from the datatable
        jawbreaker.Scoreboard.Rows.Clear();
    }

    public void startPeriodicScoreboardWriteToFile()
    {
        while (keepScoreBoardUpdated)
        {
            //three minute sleep.
            Thread.Sleep(intTimer);
            writeScoreboardToFile();
        }
    }

    public void stopPeriodicScoreboardWriteToFile()
    {
        keepScoreBoardUpdated = false;
    }

    public int IntTimer
    {
        get
        {
            return intTimer;
        }
        set
        {
            intTimer = value;
        }
    }

    public DataTable getScoreboardFromFile()
    {
        FileInfo f = new FileInfo(scoreBoardFileLocation);
        if (!f.Exists)
        {
            jawbreaker.writeInfoToLog("Scoreboard not there so creating new one");
            return setupNewScoreBoard();
        }
        else
        {
            DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
            //A 64 bit key and IV is required for this provider.
            //Set secret key For DES algorithm.
            DES.Key = ASCIIEncoding.ASCII.GetBytes(sSecretKey);
            //Set initialization vector.
            DES.IV = ASCIIEncoding.ASCII.GetBytes(sSecretKey);

            //Create a file stream to read the encrypted file back.
            FileStream fsread = new FileStream(scoreBoardFileLocation, FileMode.Open, FileAccess.Read);
            //Create a DES decryptor from the DES instance.
            ICryptoTransform desdecrypt = DES.CreateDecryptor();
            //Create crypto stream set to read and do a 
            //DES decryption transform on incoming bytes.
            CryptoStream cryptostreamDecr = new CryptoStream(fsread, desdecrypt, CryptoStreamMode.Read);

            DataTable dTable = new DataTable("scoreboard");
            dTable.ReadXml(new StreamReader(cryptostreamDecr));

            cryptostreamDecr.Close();
            fsread.Close();

            return dTable;
        }
    }

    public DataTable setupNewScoreBoard()
    {
        //scoreboard info into dataset
        DataTable scoreboard = new DataTable("scoreboard");
        scoreboard.Columns.Add(new DataColumn("playername", System.Type.GetType("System.String")));
        scoreboard.Columns.Add(new DataColumn("score", System.Type.GetType("System.Int32")));
        scoreboard.Columns.Add(new DataColumn("ballnumber", System.Type.GetType("System.Int32")));
        scoreboard.Columns.Add(new DataColumn("xsize", System.Type.GetType("System.Int32")));
        scoreboard.Columns.Add(new DataColumn("ysize", System.Type.GetType("System.Int32")));
        scoreboard.Columns.Add(new DataColumn("gametype", System.Type.GetType("System.String")));
        scoreboard.Columns.Add(new DataColumn("date", System.Type.GetType("System.DateTime")));
        scoreboard.Columns.Add(new DataColumn("synced", System.Type.GetType("System.Boolean")));

        scoreboard.AcceptChanges();
        return scoreboard;
    }

    private void Run()
    {
        // For additional security Pin the key.
        GCHandle gch = GCHandle.Alloc(sSecretKey, GCHandleType.Pinned);

        // Remove the Key from memory. 
        ZeroMemory(gch.AddrOfPinnedObject(), sSecretKey.Length * 2);
        gch.Free();
    }
}
}

Ответы [ 2 ]

4 голосов
/ 31 марта 2010

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

У меня есть два замечания из кода расшифровки:

  • Установка IV так же, как ключ, не выглядит правильно (хотя это может быть правильно, если это то, что делает ваш код шифрования)
  • Это действительно вопросительные знаки в SSecretKey? Могут ли они быть управляющими или старшими байтовыми символами, ставшими жертвами неправильного кодирования и / или неправильной вставки?

Добавлено: Спасибо за обновление. Немного гуглинга говорит о том, что плохие данные часто вызваны тем, что дешифрованные данные не являются именно теми, которые были выведены при шифровании, это место, на котором нужно сосредоточиться (но продолжайте изучать, верна ли строка ключей). Я должен признать, что немного разбираюсь в C #, поэтому ниже приведены только предположения:

  • В writeScoreboardToFile вы записываете XML в MemoryStream, а затем записываете содержимое этого потока в ваш CryptoStream. Есть ли причина, по которой вы не пишете напрямую в CryptoStream?
  • Законно ли устанавливать ms.Position напрямую? ms.Seek(0,SeekOrigin.Begin) имеет значение?
  • Возможно, вам придется позвонить cryptostream.FlushFinalBlock() перед закрытием, из MSDN не ясно, вызывается ли он автоматически.
  • Зашифрованные данные являются двоичными, вам может понадобиться использовать BinaryReader и BinaryWriter, чтобы избежать их разбивания кодировками, как указал Крис.
  • Когда именно вызывается Run()? Если я правильно понял, это обнуление строки секретного ключа - очевидно, вы не хотите, чтобы это произошло до того, как вы закончите создавать свои криптопреобразования.

Кроме того, я бы прокомментировал, что установка IV равной ключу не очень криптографически верна; IV должен действительно отличаться каждый раз, когда вы шифруете одним ключом.

0 голосов
/ 05 января 2010

Вы можете проверить эту ссылку: http://blogs.msdn.com/shawnfa/archive/2005/11/10/491431.aspx

В нем говорится о проблемах с шифрованием / дешифрованием и кодировкой ascii.

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