2011-02-23 16 views
1

私はC#と暗号化が新しくなっていますので、忍耐を持ってください。私はいくつかのバイナリデータ( "オブジェクト" - 実際にはほとんどオブジェクトの一部分しか保存しないため、シリアル化、BinaryWriterなどは使用できません)を保存したいので、メモリで暗号化してFileStream 。最初は何らかのXorを使いたいと思っていましたが、それがとても簡単であることは分かりませんでしたが、今度はAesを使うようにコードを変更しました。チャンク内のデータを暗号化/復号化する方法は?

私はいくつかの比較的大きなファイルを持っており、頻繁に32バイトのデータのように変更または読み込みが必要なだけです。したがって、私は1つのデータチャンクのみを暗号化できなければならず、また、所望のデータチャンクだけを解読することができなければならない。今のところ、私は次の解決策だけを思いついた。

データを保存すると、すべてのデータをループし、ループ内でデータのチャンクを暗号化してファイルに書き込みます。読んでいる間、私はデータの塊を読み取るループを持っていて、ループの中で私は非常に非効率的な解読器を宣言しなければなりません。

 //setup file stream for saving data 
     FileStream fStream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read, 1024, 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 encryptor = aes.CreateEncryptor(key, iv); 

     foreach(....) 
     { 
      //data manipulation 

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

キーとIVは、これは私が道のキーを変更します動作しますと、iv生成された後だけ、簡単にデバッグや問題解決を可能にするためにハードコードされています

は、ここで保存し、暗号化&ためのコードです。

ここ&解読読み取るためのコードです: のFileStream FSTREAM =新しいFileStreamを(ファイル名、FileMode.Open、FileAccess.Read、FileShare.Read、4096、偽の);

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

      //reading 
      while (numBytesToRead > 0) 
      { 
       byte[] original = new byte[32]; 
       byte[] data = new byte[32]; 
       int len = fStream.Read(original, 0, 32); 

       //error checking ... 

       //decryption 
       ICryptoTransform decryptor = aes.CreateDecryptor(key, iv); //this is a slow operation 
       MemoryStream m = new MemoryStream(); 
       using (Stream c = new CryptoStream(m, decryptor, CryptoStreamMode.Write)) 
        c.Write(original, 0, original.Length); 
       data = m.ToArray(); 

       //data manipulation ... 
      } 

私は、ループ内にデクリプタを作成することが非常に非効率的だと感じています。非常に多くのデータがあります。私はループに入る前にそれを作成すると、私は正しく復号化できず、暗号化を変更する必要があります(暗号化ストリームとメモリストリームをループの前に宣言してください)が、必要なデータだけを暗号化/復号化できません。また、ランダムな読み書きしか必要としないファイルはあまりありません。例えば、あるファイルでは、ある位置からファイルの最後まで読みたいと思うでしょう。

これはあなたの意見ですか?これを達成するより良い方法はありますか?たぶん異なる暗号化アルゴリズム(私はいくつかの種類のxorを使いたいと思っていましたが、「壊れやすい」ことがわかりました)?

p.s.私はメモリ内で暗号化したいので、シーク可能なストリームを使用する必要があります。

+0

を、それを使用する必要がブロック単位の暗号化を解除したい場合は、私はあなたがそのようなXTSのように異なる暗号化モードをしたいと仮定します。 – CodesInChaos

答えて

1

完全ランダムアクセスが必要な場合は、ECBを使用してください(earlier answerが推奨)。あなたには、前のブロックの暗号文が依存ほとんどの他のモードとは異なり、ストリーム(またはブロックの位置を入れ替えていないことがIVを使用しないため、各ブロックの暗号化ストリームを再作成する必要があり、ブロックを暗号化しないだろうストリーム)。 Wikipediaには、このモードの問題の1つであるnice illustration(暗号化画像)があります。

ファイルを論理的に(たとえば、仮想ディスク内のデータベースレコードまたはディスクセクタなど)より大きな塊で構成されている場合は、ユニットとしてそれらを暗号化することを検討すべきです。 CBCモードでは、チャンクごとに新しいランダムIVを生成し、ブロックごとに新しいランダムIVを生成し、それをブロックに格納します(チャンクごとに32バイトのストレージを追加します)。また、チャンク全体を書き直す必要があります。シングルバイトの変更が、セキュリティははるかに良いでしょう。

1

ECB暗号化モード(CipherMode.ECB)を使用できます。他の暗号化モードは、暗号および/または平文を暗号化/復号化するために次のテキストブロックにフィードバックする。これは、繰り返し部分が異なる方法で暗号化されるため、より大きなセキュリティを提供します。ただし、完全なストリームを復号化する必要があります。

電子コードブック(ECB)モードでは、各ブロックが個別に暗号化されるため、暗号ブロック境界でランダムアクセスを実装できます。しかし、ECBは脆弱性を導入しています。 See here

0

私はちょうどGCMの代わりに、ECBの使用についてのヒントを与えました。 ECBはおそらくこれを行うための安全な方法ではないと知っています。現在、Bouncy Castle APIを使用してプロトタイプを実装しています(このスレッドを確認してください:https://stackoverflow.com/a/10366194/637783)。

0

あなたが最後の8つのバイトを維持し、次のブロックのためにIVとして

while ((count = fileRead.Read(read, 0, 16)) > 0) 
       { 
        if (transed > 0) 
         aes.IV = read; 
        transed += count; 
        ... 
       } 
関連する問題