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

key 和 iv 是硬编码的,只是为了更容易调试和解决问题,一旦这可行,我将改变 key 和 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 ...
            }

好吧,我发现在循环中创建解密器效率很低。会有相当多的数据。如果我在进入循环之前创建它,那么我无法正确解密并且必须更改加密(在循环之前声明加密流和内存流),但是我不能只加密/解密所需的数据块。也没有多少文件只需要随机读/写。例如,在某些文件中,我想从某个位置读取到文件末尾,这可能会很多。

您对此有何看法?有没有更好的方法来实现这一目标?也许不同的加密算法(一开始我想使用某种异或,但我发现它很容易“破解”)?

ps 我想在内存中加密,我必须使用可搜索的流。

4

4 回答 4

1

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

使用电子密码本 (ECB) 模式,每个块都单独加密,因此您可以在密码块边界实现随机访问。然而,ECB 引入了漏洞,尤其是当纯文本重复时。 看这里

于 2011-02-23T11:59:32.003 回答
1

如果您想要完全随机访问,ECB 是要走的路(正如之前的答案所建议的那样)。您不需要为每个块重新创建加密流,因为它不使用 IV 并且加密块不会置换流(与大多数其他模式不同,其中密文取决于先前的块或块在流)。Wikipedia 有一个很好的说明(密码图片)说明了这种模式的一个问题。

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

于 2011-02-23T16:17:51.180 回答
0

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

于 2012-09-07T08:27:58.313 回答
0

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

while ((count = fileRead.Read(read, 0, 16)) > 0)
                {
                    if (transed > 0)
                        aes.IV = read;
                    transed += count;
                    ...
                }
于 2017-06-29T09:41:53.903 回答