1

私はC#にかなり慣れていないので、これを許してください。私はこれで長い間頭を壁にぶつけていましたが、解決策が見つかりません. おそらくそれは非常に明白なことです。

オブジェクトのプロパティをファイルに書き込んでいます。最初にプロパティをバイト配列に変換し、次に配列全体 (「1 つのオブジェクト」) をまとめて、Aes を使用して MemoryStream 経由で暗号化します。シリアル化やその他の可能性については知っていますが、本当にこの方法で行う必要があります。他の方法では、このファイルをチャンク (「オブジェクト」) で読み取り、復号化し、バイト配列からオブジェクト プロパティを再構築します。問題は、最初のレコード (「オブジェクト」) のみが復号化され、正常に/正しく再構築されることです。他のすべてのデータはめちゃくちゃになります (int は 2 ではなく 48464 の値を取得し、文字列は奇数の符号を示し、double は 20 ではなく -3.16...E-161 になります...)。

そして、私には理由がわかりません。考えられる限りのことはすべて試しました。暗号化と復号化をコメントアウトするとすべてが機能するので、書き込みと読み取りには問題ありません。オブジェクトの復号化と再構築のコードを暗号化のコードのすぐ下に配置すると (書き込まれたデータ チャンクを復号化するため)、すべてが適切に復号化および再構築されるため、復号化と再構築の問題にはなりません。しかし、それがすべて一緒になると、それはめちゃくちゃになります。私はここで本当に迷っています。

私がデータを操作する方法に集中しないでください。今はそれほど重要ではありません。なぜこのようにするのかには理由があります。

ファイルに保存するためのコード全体を次に示します。

//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 への変換や「or」などの使用など) は部分的に圧縮が原因です。

これを解決するのを手伝ってください。また、データの取り扱いに集中したり、シリアライゼーションやバイナリライターなどを使用するようにアドバイスしたりしないでください。本当に理由があります。

私は完全にアイデアがないので、本当にあなたを頼りにしています。皆様、貴重なお時間とご回答ありがとうございます。

4

2 に答える 2

2

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);
    }
}
于 2011-02-22T23:52:54.477 に答える
0

CryptoStreamは他のストリームと同じように使用されます。つまり、 a をラップして に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)、元のファイルとストリーム オブジェクトをできるだけ早く閉じることをお勧めします。)

于 2011-02-22T22:08:00.807 に答える