c# - 加密文件大小的计算与真实大小不匹配

标签 c# encryption rijndaelmanaged equation encryption-symmetric

我需要计算我使用 Rijndael 加密的文件的大小。

根据本站和谷歌上的其他答案,以下是计算加密数据长度的正确方法:

EL = UL + (BS - (UL Mod BS) Mod BS)

Where: 
EL = Encrypted Length
UL = Unencrypted Length
BS = Block Size

在我的例子中,未加密的文件长度为 5,101,972 字节,我使用 128 位加密 key , block 大小为 16 字节。 因此,等式为:

EL = 5101972 + (16 - (5101972 Mod 16) Mod 16)
EL = 5101972 + (16 - 4 Mod 16)
EL = 5101972 + (12 Mod 16)
EL = 5101972 + 12
EL = 5101984

给出一个长度为 5,101,984 字节的加密文件

但是,加密后我的文件大小为 5,242,896 140,912 字节的大小差异巨大!

现在..我显然做错了什么,但我无法弄清楚它是什么。 下面是我的加解密测试代码,以及计算加密大小的方法:

private static void Enc(string decryptedFileName, string encryptedFileName)
{
    PasswordDeriveBytes passwordDB = new PasswordDeriveBytes("ThisIsMyPassword", Encoding.ASCII.GetBytes("thisIsMysalt!"), "MD5", 2);
    byte[] passwordBytes = passwordDB.GetBytes(128 / 8);

    using (FileStream fsOutput = File.OpenWrite(encryptedFileName))
    {
        using(FileStream fsInput = File.OpenRead(decryptedFileName))
        {
            byte[] IVBytes = Encoding.ASCII.GetBytes("1234567890123456");

            fsOutput.Write(BitConverter.GetBytes(fsInput.Length), 0, 8);
            fsOutput.Write(IVBytes, 0, 16);

            RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC,Padding=PaddingMode.Zeros};
            ICryptoTransform encryptor = symmetricKey.CreateEncryptor(passwordBytes, IVBytes);

            using (CryptoStream cryptoStream = new CryptoStream(fsOutput, encryptor, CryptoStreamMode.Write))
            {
                for (long i = 0; i < fsInput.Length; i += chunkSize)
                {
                    byte[] chunkData = new byte[chunkSize];
                    int bytesRead = 0;
                    while ((bytesRead = fsInput.Read(chunkData, 0, chunkSize)) > 0)
                    {
                        cryptoStream.Write(chunkData, 0, chunkSize);
                    }
                }
            }
        }
    }            
}

private static void Dec(string encryptedFileName, string decryptedFileName)
{
    PasswordDeriveBytes passwordDB = new PasswordDeriveBytes("ThisIsMyPassword", Encoding.ASCII.GetBytes("thisIsMysalt!"), "MD5", 2);
    byte[] passwordBytes = passwordDB.GetBytes(128 / 8);

    using (FileStream fsInput = File.OpenRead(encryptedFileName))
    {
        using (FileStream fsOutput = File.OpenWrite(decryptedFileName))
        {
            byte[] buffer = new byte[8];
            fsInput.Read(buffer, 0, 8);

            long fileLength = BitConverter.ToInt64(buffer, 0);

            byte[] IVBytes = new byte[16];
            fsInput.Read(IVBytes, 0, 16);


            RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC,Padding=PaddingMode.Zeros};
            ICryptoTransform decryptor = symmetricKey.CreateDecryptor(passwordBytes, IVBytes);

            using (CryptoStream cryptoStream = new CryptoStream(fsOutput, decryptor, CryptoStreamMode.Write))
            {
                for (long i = 0; i < fsInput.Length; i += chunkSize)
                {
                    byte[] chunkData = new byte[chunkSize];
                    int bytesRead = 0;
                    while ((bytesRead = fsInput.Read(chunkData, 0, chunkSize)) > 0)
                    {
                        cryptoStream.Write(chunkData, 0, bytesRead);
                    }
                }
                fsOutput.SetLength(fileLength);
            }                    
        }
    }
}

private static void CalcEncSize(string decryptedFileName)
{
    FileInfo fi = new FileInfo(decryptedFileName);
    if (fi.Exists)
    {                
        long blockSize = 128/8;
        long fileLength = fi.Length;
        long encryptedSize = fileLength + ((blockSize - (fileLength % blockSize)) % blockSize);
        encryptedSize += 24; //16 bytes for the IV, and 8 more for the filelength, both stored at the start of the file.

        Console.WriteLine("Estimated Encryption Size: " + encryptedSize.ToString());           
    }
}

注意:在开始的计算中,我不包括我自己在加密文件开头使用的额外24个字节来存储原始文件长度,以及IV ...我知道这一点,但是不想让等式变得不必要的复杂。

最佳答案

您不应该在实际加密过程之前写入输出文件。 CryptoStream 将在关闭时处理所有必要的填充。此外,for 循环不是必需的,因为内部 while 循环将读取整个文件。此外,您应该只写与从文件中读取的一样多的内容。试试这些改变。

private static void Enc(string decryptedFileName, string encryptedFileName)
{
    PasswordDeriveBytes passwordDB = new PasswordDeriveBytes("ThisIsMyPassword", Encoding.ASCII.GetBytes("thisIsMysalt!"), "MD5", 2);
    byte[] passwordBytes = passwordDB.GetBytes(128 / 8);

    using (FileStream fsOutput = File.OpenWrite(encryptedFileName))
    {
        using(FileStream fsInput = File.OpenRead(decryptedFileName))
        {
            byte[] IVBytes = Encoding.ASCII.GetBytes("1234567890123456");

            RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC,Padding=PaddingMode.Zeros};
            ICryptoTransform encryptor = symmetricKey.CreateEncryptor(passwordBytes, IVBytes);

            using (CryptoStream cryptoStream = new CryptoStream(fsOutput, encryptor, CryptoStreamMode.Write))
            {
                byte[] chunkData = new byte[chunkSize];
                int bytesRead = 0;
                while ((bytesRead = fsInput.Read(chunkData, 0, chunkSize)) > 0)
                {
                    cryptoStream.Write(chunkData, 0, bytesRead);  //KEY FIX
                }
            }
        }
    }            
}

[编辑]

哦,我错过了很多信息。我误读了您的尺寸,认为 140,912 是尺寸,而不是差异。现在我看到了,我可以做出更容易理解的回应。根据您的代码,大小差异应该与您的 block 大小相当。由于 chunkSize 可能有点大,您的代码通常会写入 chunkSize 比实际输入文件中更多的数据(正如 Greg 和 caf 指出的那样)。我标记的行是造成差异的原因。

关于c# - 加密文件大小的计算与真实大小不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3354749/

相关文章:

encryption - 当 AesManaged.FeedbackSize = 128 时,为什么 AesManaged.FeedbackSizeValue = 8

android - .NET 中的加密和 Android 中的解密抛出 BadPaddingException : pad block corrupted

c# - Xamarin iOS CGPath 绘制带有弯角/圆角的多边形

c# - 为什么其他不可变类型没有 StringBuilder 的等价物?

java - 必需的 String[] 找到 String Java

python - 从单个列表创建多个列表

C# - TakeWhile 和 SkipWhile 不返回?

c# - 双向绑定(bind) View 的 DependencyProperty 到 View 模型的属性?

c# - Java/.NET 中的 RSA 加密和 .NET 中的解密

c# - 预测加密字符串的长度