如何以块的形式加密/解密数据?

时间:2011-02-23 11:26:56

标签: c# save encryption chunks

我对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 = 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;

            //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。我想在内存中加密,我必须使用可搜索的流。

4 个答案:

答案 0 :(得分:1)

您可以使用ECB加密模式(CipherMode.ECB)。其他加密模式将密码和/或纯文本反馈到下一个文本块以进行加密/解密。这提供了更高的安全性,因为重复的部分以不同的方式加密。但是,它需要解密整个流。

使用电子代码簿(ECB)模式,每个块都是单独加密的,因此您可以在密码块边界实现随机访问。但是,ECB引入了漏洞,特别是当纯文本重复时。 See here

答案 1 :(得分:1)

如果您想要完全随机访问,可以选择ECB(如earlier answer建议的那样)。您不需要为每个块重新创建加密流,因为它不使用IV并且加密块不会置换流(与密码文本依赖于先前块或块中位置的大多数其他模式不同)流)。维基百科有一个nice illustration(ciphertux图片)这个模式的一个问题。

如果您的文件逻辑上包含较大的块(例如数据库记录或虚拟磁盘中的磁盘扇区),则应考虑将它们加密为单位。在CBC模式下,每次编写时都会为每个块生成一个新的随机IV,并将其与块一起存储(因此每个块使用额外的32个字节的存储空间),即使是一个块,您也需要重写整个块。单字节更改,但安全性会好得多。

答案 2 :(得分:0)

我刚刚给出了关于使用GCM而不是ECB的提示。您可能知道ECB不是一种非常安全的方法,我目前正在使用Bouncy Castle API实现原型(请查看此主题:https://stackoverflow.com/a/10366194/637783)。

答案 3 :(得分:0)

如果要逐块解密,则必须保留最后8个字节并将其用作下一个块的IV

while ((count = fileRead.Read(read, 0, 16)) > 0)
                {
                    if (transed > 0)
                        aes.IV = read;
                    transed += count;
                    ...
                }