【问题标题】:.NET file Decryption - Bad Data.NET 文件解密 - 错误数据
【发布时间】:2010-04-01 06:10:31
【问题描述】:

我正在重写一个旧应用程序。旧应用程序将数据存储在记分牌文件中,该文件使用以下代码加密:

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

这很好用。我已将代码复制到我的新应用程序中,以便我可以创建旧版加载器并将数据转换为新格式。问题是我收到“错误数据”错误:

System.Security.Cryptography.CryptographicException 未处理 消息="错误数据。\r\n" 来源="mscorlib"

错误在这一行触发:

dTable.ReadXml(new StreamReader(cryptostreamDecr));

加密文件今天是在使用旧代码的同一台机器上创建的。我猜可能加密/解密过程使用了应用程序名称/文件或其他内容,因此意味着我无法打开它。

有没有人知道:

A) 能够解释为什么这不起作用? B) 请提供一个解决方案,让我能够打开使用旧应用程序创建的文件并能够转换它们?

这是处理加载和保存记分牌的整个类:

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

【问题讨论】:

  • 只是一个松散的观察:不管你的加密有多好。如果您将加密作为字符串存储在您的应用中,那么它是不安全的。
  • 嗨 Reinier,完全同意。记分牌只是为了一个小游戏而设计的,目的是为了阻止最明显的作弊行为。我没有研究更安全的方法来做到这一点,因为它似乎是过度杀戮。感谢您的意见:)
  • 大多数情况下,出现这个异常的原因是,写完最后一个字节的数据后忘记调用cryptostreamDecr.FlushFinalBlock()。

标签: c# .net cryptography encryption


【解决方案1】:

这看起来像是解密文件并从中反序列化记分牌对象的代码。我们真的需要看看原始的加密端来比较,如果你可以发布的话。

我从解密代码中有两个观察结果:

  • 将 IV 设置为与密钥相同看起来不正确(尽管如果您的加密代码正在这样做,它可能是正确的)
  • 这些真的是 SSecretKey 中的问号吗?它们是控制字符还是高字节集字符成为错误编码和/或错误粘贴的牺牲品?

已添加:感谢您的更新。一些谷歌搜索表明,坏数据通常是由于解密的数据与加密输出的数据不完全相同,这是一个需要关注的地方(但请继续查看密钥字符串是否正确)。我必须承认我对 C# 的理解有点不够深入,所以以下只是建议:

  • writeScoreboardToFile 中,您将 XML 写入 MemoryStream,然后将该流的内容写入您的 CryptoStream。您有什么理由不直接写入 CryptoStream 吗?
  • 直接设置ms.Position是否合法? ms.Seek(0,SeekOrigin.Begin) 有什么不同吗?
  • 你可能需要在关闭之前调用cryptostream.FlushFinalBlock(),从MSDN不清楚是否自动调用。
  • 加密数据是二进制的,正如 Chris 指出的那样,您可能需要使用 BinaryReaderBinaryWriter 以避免它被编码破坏。
  • 究竟什么时候调用Run()?如果我理解正确,那就是将密钥字符串归零 - 显然您不希望在完成加密转换之前发生这种情况。

除此之外,我要评论的是,将 IV 设置为等于密钥在密码学上不是很合理;每次使用一个密钥加密时,IV 都应该是不同的。

【讨论】:

  • 您好,感谢您的意见。我已经为你添加了完整的代码。是的,我认为它们是问号。我想,将不得不回到旧的东西来检查。
【解决方案2】:

您可能想查看此链接:http://blogs.msdn.com/shawnfa/archive/2005/11/10/491431.aspx

它谈到了加密/解密和ascii编码的问题。

【讨论】:

  • 我可能误解了这篇文章,但我认为这不是我的问题。尽管将来可能会成为一个问题,例如多语言的东西。旧版应用程序可以毫无问题地打开文件,我已经复制了代码,(剪切并粘贴)到新应用程序中并运行它。如果旧应用没有问题,我不确定为什么新应用会出现问题。
  • 如果旧应用程序是用.net 1.1 编写的,而新应用程序是用.net 2.0 或更高版本编写的,那么ascii 编码将是一个大问题。主要是因为他们在 2.0 框架中“修复”了它……
  • 所以你需要摆脱所有 ASCII 编码的东西
  • 它们都是用 2.0 编写的(实际上新版本可能针对 3.5)。将尝试重写它,看看会发生什么,谢谢:)
猜你喜欢
  • 2012-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-03
  • 1970-01-01
  • 1970-01-01
  • 2017-10-11
相关资源
最近更新 更多