2011-02-23 63 views
1

我對C#和加密很新,所以請耐心等待。我想保存一些二進制數據(「對象」 - 事實上大部分只是對象的一部分,因此我不能/不使用序列化,BinaryWriter等),我想在內存中加密它,然後使用FileStream 。起初我想使用某種Xor,但我不知道它很容易破壞,現在我改變了代碼來使用Aes。如何在數據塊中加密/解密數據?

事情是我會有一些相對較大的文件,而且我經常只需要更改或讀取像32字節的數據。因此,我必須能夠僅加密一塊數據,並且只能解密所需的數據塊。現在我只想出下面的解決方案。

當保存數據時,我循環遍歷所有數據並在循環中加密一塊數據並將其寫入文件。在閱讀時,我有循環讀取數據塊,並且在循環中我必須聲明解密器,而我發現它非常低效。

這裏是保存加密&代碼:

 //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 ... 
      } 

那麼,事情是,我覺得它是非常低效的創建一個循環中的解密器。將會有相當多的數據。如果我在進入循環之前創建它,那麼我無法正確解密,必須更改加密(在循環之前聲明加密流和內存流),但是我無法僅加密/解密所需的大塊數據。也沒有太多隻需要隨機讀取/寫入的文件。例如,在某些文件中,我想從某個位置讀到文件結尾,這可能相當多。

您對此有何看法?有沒有更好的方法來實現這一目標?也許不同的加密算法(一開始我想使用某種異或,但我發現它很容易「破解」)?

p.s.我想在內存中加密,我必須使用可搜索的流。

+0

我假設你想要一個不同的加密模式,如XTS。 – CodesInChaos 2011-02-23 11:43:03

回答

1

如果你想完全隨機存取,ECB是最好的選擇(如earlier answer建議)。您不需要爲每個塊重新創建加密流,因爲它不使用IV並且加密塊不會對流進行置換(與大多數其他模式不同,後者根據先前的塊或塊的位置流)。維基百科有一個nice illustration(ciphertux圖片)這種模式的問題之一。

如果您的文件在邏輯上由較大的塊組成(如虛擬磁盤中的數據庫記錄或磁盤扇區),則應考慮將它們作爲單元加密。在CBC模式下,每次寫入塊並將其與塊一起存儲(因此每塊需要額外存儲32個字節)時,您將爲每個塊產生一個新的隨機IV,並且您需要重寫整個塊,即使單字節更改,但安全性會更好。

1

您可以使用ECB加密模式(CipherMode.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; 
        ... 
       }