2011-02-23 34 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; 
        ... 
       }