2010-07-28 158 views
4

我需要计算使用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个字节一个加密文件长度。

但是,我的文件在加密后的大小在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("123456789"); 

      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 ...我知道这一点,但不希望复杂的方程超过必要的。

+0

chunkSize的值是多少? – SwDevMan81 2010-07-28 16:00:28

+0

块大小目前是16个字节。 但是,就我所知,这对整体加密大小没有影响(使用16的增量,从16到10240) – Sk93 2010-07-28 16:02:04

+0

这是您用于大文件的原因吗?我想象你使用了更大的东西 – SwDevMan81 2010-07-28 16:05:12

回答

4

在实际加密过程之前,您不应写入输出文件。当关闭时,CryptoStream将处理所有必要的填充。此外for循环不是必需的,因为inner 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("123456789"); 

      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是大小,而不是差异。现在我明白了,我可以做出更明智的回应。根据您的代码,大小的差异应该与您的块大小相当。由于chunkSize可能有点大,因此您的代码通常会写入更多的数据,而不是实际在输入文件中的数据(如Greg和caf指出的那样)。我标出的行是之间的差异。

+0

你能解释为什么我不能在加密之前写入流中吗? 我写在一开始的数据(前24个字节),不希望被加密的,因为我需要它来解密方法的其余部分。 它实际上似乎没有任何区别,如果我使用CHUNKSIZE,或bytesRead,作为chuckData阵列中的任何未使用的字节都只是空的,似乎没有得到由cryptoStream.Write()方法反正编码。 如果不是这种情况,就不会这样肯定造成负面影响的加密/解密过程中,其工作完全正常? – Sk93 2010-07-28 16:21:45

+0

至于写入加密文件之前,我想这将是罚款。只需要记住,如果您尝试解密,则需要偏移这些写入的字节以正确解密数据。它确实不应该影响加密过程,但会解密。我会更新我的答案,直接解决似乎导致问题的原因。 – 2010-07-28 16:47:01

+0

对不起,我得考虑一下。我以为我会有一个合理的解释,但现在不要(而且我时间紧迫)。我已经帮助了另一个几乎完全相同的问题,但没有听到最终结果。我会就此回复你。 – 2010-07-28 17:08:12