代码之家  ›  专栏  ›  技术社区  ›  Sk93

加密文件大小的计算与实际大小不匹配

  •  4
  • Sk93  · 技术社区  · 14 年前

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

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

    EL = UL + (BS - (UL Mod BS) Mod BS)
    
    Where: 
    EL = Encrypted Length
    UL = Unencrypted Length
    BS = Block Size
    

    在我的例子中, 未加密的文件长度为5101972字节 ,我正在使用一个128位的加密密钥,给我一个 块大小为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
    

    给予一个 加密文件长度为5101984字节 .

    但是,加密后我的文件大小为5242896 140912字节大小的巨大差异!

    现在。。显然我做错了什么,但我搞不清是什么。 下面是我的加密和解密测试代码,以及用于计算加密大小的方法:

    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…我知道这一点,但不想把方程复杂化。

    1 回复  |  直到 14 年前
        1
  •  4
  •   Jeff Mercado    14 年前

    您不应该在实际加密过程之前写入输出文件。这个 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
                    }
                }
            }
        }            
    }
    

    [编辑]

    哦,我错过了很多信息。我误解了你认为140912是什么尺寸,不是什么区别。现在我明白了,我可以做出更清晰的反应。根据您的代码,大小上的差异应该与块大小相当。因为chunksize可能有点大,所以通常情况下,代码编写的chunksize数据比实际输入文件中的数据多(如greg和caf指出的)。我标记的行是 这个 差异的原因。