【问题标题】:Proper C# Rijndael IV Usage/Storage正确的 C# Rijndael IV 使用/存储
【发布时间】:2012-10-21 14:40:15
【问题描述】:

下午,

所以我对所有这些加密方法和用法都很陌生。我刚刚开始构建加密实现。现在我的加密和解密方法似乎工作正常。直到我读到我在 RijndaelManaged 类中使用硬编码 IV 失败了。

我到处都在阅读,最好(也更安全)让每个加密文件的 IV 在“加密时间”唯一生成并保存在文件的前面/开头,而其余的加密字节在之后直接保存这个。 (如果我理解正确的话)

我一直很难弄清楚我的问题,因为每次加密文件时,我都会将 IV 写入前 16 个字节(正如班级、MSDN、Google 和该论坛上的一些人所建议的那样)文件,然后直接将其余的加密字节写入文件流。 (IV 以明文形式保存..或未加密的字节

我的问题是,当我尝试使用完全相同的密钥解密文件时它失败了:在我开始读取文件的块进行解密(缓冲)之前,我尝试读取文件的前 16 个字节以获取明文 IV 和在 RijndaelManaged Class 实例中使用它。

这似乎失败了。我检查了一下,我想我可能在某处犯了一些小学生错误:因为一旦我想解密它,我似乎无法从加密文件中读取相同的 16 个字节。

这是我用来在加密之前进行文件处理的代码(不是它自己的加密)


using (RijndaelManaged RM = new RijndaelManaged())
using (FileStream StreamIN = new FileStream(FileIN, FileMode.Open, FileAccess.Read))
using (FileStream StreamOUT = new FileStream(FileOUT, FileMode.Append, FileAccess.Write))
{
    //Setup Variable ChunkSize and The Total bytes Read into the streams
    int ChunkSize = 1024 * 1024 * 32; 

    RM.GenerateIV();

    foreach (var item in RM.IV)
    {
        Console.Write("[ " + item + "] ");
    }

    StreamOUT.Seek(0, SeekOrigin.Begin);
    StreamOUT.Write(RM.IV, 0, RM.IV.Length);
    StreamOUT.Seek(RM.IV.Length, SeekOrigin.Begin);

    int TotalBytesRead = 0;                       

    //File Buffer Implementation
    for (long i = 0; i < StreamIN.Length; i += ChunkSize)
    {
        //ChunkData byte array determined by ChunkSize
        byte[] ChunkData = new byte[ChunkSize];
        //Current Bytes Read from the IN Stream
        int BytesRead = 0;
        while ((BytesRead = StreamIN.Read(ChunkData, 0, ChunkSize)) > 0)
        {
            //Call Encryption from local Class

            Console.WriteLine("Bytes Read: {0}", TotalBytesRead += BytesRead);

            ChunkData = Crypt.Encrypt(ChunkData, KeyBytes, RM.IV);

            //Write byte array to File
            StreamOUT.Write(ChunkData, 0, BytesRead);
        }
    }
}

这是我在解密之前处理文件的代码(不是解密本身)

using (RijndaelManaged RM = new RijndaelManaged())
using (FileStream StreamIN = new FileStream(FileIN, FileMode.Open, FileAccess.Read))
using (FileStream StreamOUT = new FileStream(FileOUT, FileMode.Append, FileAccess.Write))
{
    //Setup Variable ChunkSize and The Total bytes Read into the streams
    int ChunkSize = 1024 * 1024 * 32; 


    StreamIN.Seek(0, SeekOrigin.Begin);
    int Read = StreamIN.Read(RM.IV, 0, 16);
    StreamIN.Seek(RM.IV.Length, SeekOrigin.Begin);

    int TotalBytesRead = 0;

    foreach (var item in RM.IV)
    {
        Console.Write("[ " + item + "] ");
    }

    //File Buffer Implementation
    for (long i = 0; i < StreamIN.Length; i += ChunkSize)
    {
        //ChunkData byte array determined by ChunkSize
        byte[] ChunkData = new byte[ChunkSize];
        //Current Bytes Read from the IN Stream
        int BytesRead = 0;

        while ((BytesRead = StreamIN.Read(ChunkData, 0, ChunkSize)) > 0)
        {

            Console.WriteLine("Bytes Read: {0}", TotalBytesRead += BytesRead);                                

            //Call Decryption from local Class
            ChunkData = Crypt.Decrypt(ChunkData, KeyBytes, RM.IV);

            //Write byte Array to file
            StreamOUT.Write(ChunkData, 0, BytesRead);
        }
    }
}

我想这就是全部了吗?此外,“控制台”和其他无用的调用只是为了帮助我检查和找出问题所在。 我正在使用 Visual Studios 2010,并尝试实现 RijndaelManaged 类。

加密/解密方法通过我的密钥和 IV 传递给 FileChunks(字节数组),它们返回一个字节数组(加密),它被保存到流中。

我希望我的问题很清楚?如果不是我会尝试更好地解释, 我到处阅读以寻求有关此特定问题的帮助,但此处发布的大多数其他问题超出了我的范围。

我真的很感激任何帮助,我确定我在某个地方犯了一个小丑错误..

谢谢!!

【问题讨论】:

  • 哇有人想要正确使用 IV。多么罕见的景象。
  • 我怀疑问题行是int Read = StreamIN.Read(RM.IV, 0, 16);RM.IV 正在返回一个字节数组,您可以填充该数组,但为了设置 IV,该属性必须分配一个值。所以最好读入显式分配的数组,然后设置RM.IV等于数组。
  • 那么,您在加密和解密中看到了不同的 IV?提供更多细节:完全或部分不同,解密器中有多少字节? int Read 的值是多少?
  • @shambulator:根据您的建议,我明确地将 RM.IV 分配给读取的字节。这解决了我遇到的问题!我非常感谢您的时间!请享受一个愉快的夜晚/白天/无论如何:D
  • @HenkHolterman:在修复之前,IV 完全不同。根据控制台foreach调用加密前和解密前IV的显示,它们甚至没有一个字节匹配。但是问题已经解决了。再次感谢!

标签: c# bytearray rijndael initialization-vector


【解决方案1】:

根据长期存在的Framework guidelines,看起来SymmetricAlgorithm.IV 已被编写为不返回内部数组。这意味着它会将副本交还给您,因此对其进行的后续更改不会反映在 RijndaelManaged 实例中。

// Effectively reading the persisted value into a temporary array
// and throwing away the temporary.
int Read = StreamIN.Read(RM.IV, 0, 16);

为了使更改生效并将 IV 设置为持久值,您需要明确设置 IV 属性,而不仅仅是修改它之前返回的值。

byte[] persistedIv = new byte[16];
StreamIN.Read(persistedIv, 0, persistedIv.Length);
RM.IV = persistedIv;

【讨论】:

  • 我现在明白我的错了,再次感谢你。我应该不这样实现它 - 但我完全忽略了这一点,并开始指责其他可能的来源.. +1!
猜你喜欢
  • 2011-03-08
  • 2017-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多