【问题标题】:c# RijndaelManaged encryption & decryption sometimes failsc# RijndaelManaged 加解密有时会失败
【发布时间】:2017-03-21 16:13:26
【问题描述】:

编辑:已解决 - 问题是解密功能。更正的解密函数可以在下面的答案中找到。

我在工作的最后一天试图找出我在执行 AES 时出了什么问题。我们需要能够加密/解密大文件,所以我使用了文件流并将每个块写入磁盘。 AES 是一项要求,因为这需要与使用 AES/CBC/PKCS5Padding(据我所知相当于 PKCS7/CBC)的 Java 编写的现有系统一起使用

此实现适用于大多数文件。但是,有一些文件缺少最后 5 个字节的原始数据。该文件将毫无错误地解密,但是哈希不匹配,并且丢失的字节是真实数据和尾随零的组合。

需要注意的是,这些流在加密前后都是gzip压缩的(代码在底部)。

加密

    public static void AesEncrypt(byte[] keyBytes, byte[] ivBytes, Stream dataStream, FileStream outStream)
    {
        RijndaelManaged symmetricKey = new RijndaelManaged();
        symmetricKey.Mode = CipherMode.CBC;
        symmetricKey.Padding = PaddingMode.PKCS7;
        symmetricKey.BlockSize = 128;
        symmetricKey.KeySize = 256;

        const int chunkSize = 4096;//1024 * 1024 * 10;

        using (ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, ivBytes))
        {
            using (CryptoStream cryptoStream = new CryptoStream(outStream, encryptor, CryptoStreamMode.Write))
            {
                while (dataStream.Position != dataStream.Length)
                {
                    long remainingBytes = dataStream.Length - dataStream.Position;
                    var buffer = chunkSize > remainingBytes ? new byte[(int)remainingBytes] : new byte[chunkSize];

                    dataStream.Read(buffer, 0, buffer.Length);
                    cryptoStream.Write(buffer, 0, buffer.Length);
                    cryptoStream.Flush();
                }
                cryptoStream.FlushFinalBlock();
            }
        }
        symmetricKey.Clear();
    }

解密

    public static void AesDecrypt(byte[] keyBytes, byte[] ivBytes, Stream dataStream, FileStream outStream)
    {
        RijndaelManaged symmetricKey = new RijndaelManaged();
        symmetricKey.Mode = CipherMode.CBC;
        symmetricKey.Padding = PaddingMode.PKCS7;
        symmetricKey.BlockSize = 128;
        symmetricKey.KeySize = keyBytes.Length == 32 ? 256 : 128;

        const int chunkSize = 4096;

        using (ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, ivBytes))
        {
            using (CryptoStream cryptoStream = new CryptoStream(dataStream, decryptor, CryptoStreamMode.Read))
            {
                while (dataStream.Position != dataStream.Length)
                {
                    long remainingBytes = dataStream.Length - dataStream.Position;
                    var buffer = chunkSize > remainingBytes
                        ? new byte[(int) remainingBytes]
                        : new byte[chunkSize];

                    cryptoStream.Read(buffer, 0, buffer.Length);
                    outStream.Write(buffer, 0, buffer.Length);
                    outStream.Flush();
                }
                //cryptoStream.FlushFinalBlock(); // Was throwing an exception
            }
        }
        symmetricKey.Clear();
    }

压缩(加密前)

    public static void StreamCompress(Stream dataStream, FileStream outStream)
    {
        dataStream.Position = 0;
        outStream.Position = 0;

        const int chunkSize = 4096;
        using (GZipStream gzs = new GZipStream(outStream, CompressionMode.Compress))
        {
            while (dataStream.Position != dataStream.Length)
            {
                long remainingBytes = dataStream.Length - dataStream.Position;
                var buffer = chunkSize > remainingBytes ? new byte[(int)remainingBytes] : new byte[chunkSize];
                dataStream.Read(buffer, 0, buffer.Length);
                gzs.Write(buffer, 0, buffer.Length);
                gzs.Flush();
            }
        }
    }

解压(解密后)

    public static void StreamDecompress(Stream dataStream, FileStream outStream)
    {
        byte[] buffer = new byte[4096];
        dataStream.Position = 0;
        using (GZipStream gzs = new GZipStream(dataStream, CompressionMode.Decompress))
        {
            for (int r = -1; r != 0; r = gzs.Read(buffer, 0, buffer.Length))
                if (r > 0) outStream.Write(buffer, 0, r);
        }
}

我已经解决了一些其他问题,但无法弄清楚为什么这只发生在某些文件上。失败的文件大小为 46,854,144 字节。不过,这似乎适用于越来越大的文件。

任何帮助将不胜感激。

【问题讨论】:

  • Stream.Read() 返回一个 int 指示已读取的字节数。虽然它可能无法解决您的问题,但我强烈建议使用此返回值来确定 实际 读取了多少字节,因此应该将其写入您的输出,而不是假设缓冲区始终是完整的填充。例如:var bytesRead = inStream.Read(buffer, 0, buffer.Length); outStream.Write(buffer, 0, bytesRead);.
  • 或者直接使用Stream.CopyTo
  • 感谢您的回复!我已经添加了“bytesRead”变量,并且除了已经在执行此操作的解压缩方法之外,我都在使用它。不幸的是它还没有解决这个问题 - 我还在调查这个:(

标签: c# encryption cryptography padding missing-data


【解决方案1】:

问题在于我解密数据的方式。我错误地使用了 CryptoStream。如果有人感兴趣,更新的解密功能如下。

    public static void AesDecrypt(byte[] keyBytes, byte[] ivBytes, Stream dataStream, FileStream outStream)
    {
        dataStream.Position = 0;
        outStream.Position = 0;

        RijndaelManaged symmetricKey = new RijndaelManaged();
        symmetricKey.Mode = CipherMode.CBC;
        symmetricKey.Padding = PaddingMode.PKCS7;
        symmetricKey.BlockSize = 128;
        symmetricKey.KeySize = keyBytes.Length == 32 ? 256 : 128;

        const int chunkSize = 4096;

        using (ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, ivBytes))
        {
            using (CryptoStream cryptoStream = new CryptoStream(outStream, decryptor, CryptoStreamMode.Write))
            {

                while (dataStream.Position != dataStream.Length)
                {
                    long remainingBytes = dataStream.Length - dataStream.Position;
                    var buffer = chunkSize > remainingBytes
                        ? new byte[(int) remainingBytes]
                        : new byte[chunkSize];

                    var bytesRead = dataStream.Read(buffer, 0, buffer.Length);
                    cryptoStream.Write(buffer, 0, bytesRead);   
                }
                cryptoStream.FlushFinalBlock();
            }
        }
        symmetricKey.Clear();
    }

【讨论】:

    猜你喜欢
    • 2011-10-27
    • 2019-04-08
    • 1970-01-01
    • 1970-01-01
    • 2023-01-30
    • 1970-01-01
    • 2013-03-16
    • 1970-01-01
    • 2018-02-23
    相关资源
    最近更新 更多