对大文件使用Rijndael加密

我需要安全地加密/解密n长度的文件,理想情况下使用Rijndael,但绝对是256位加密。

我以前玩过加密,并且非常高兴地加密/解密字符串和字节数组。 但是,因为我不知道文件的大小(并且所讨论的文件可能非常大(~2.5gb)非常可行,我不能只将它们加载到字节数组中并对它们进行加密/解密像我以前一样受限制。

因此,经过对Google的一些阅读后,我知道答案是以块的forms加密和解密文件,因此我生成了以下代码:

private static void Enc(string decryptedFileName, string encryptedFileName) { FileStream fsOutput = File.OpenWrite(encryptedFileName); 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}; ICryptoTransform encryptor = symmetricKey.CreateEncryptor(passwordDB.GetBytes(256 / 8), IVBytes); CryptoStream cryptoStream = new CryptoStream(fsOutput, encryptor, CryptoStreamMode.Write); for (long i = 0; i < fsInput.Length; i += chunkSize) { byte[] chunkData = new byte[chunkSize]; fsInput.Read(chunkData, 0, chunkSize); cryptoStream.Write(chunkData, 0, chunkData.Length); } cryptoStream.Close(); fsInput.Close(); fsInput.Dispose(); cryptoStream.Dispose(); } private static void Dec(string encryptedFileName, string decryptedFileName) { FileStream fsInput = File.OpenRead(encryptedFileName); 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 }; ICryptoTransform decryptor = symmetricKey.CreateDecryptor(passwordDB.GetBytes(256 / 8), IVBytes); CryptoStream cryptoStream = new CryptoStream(fsOutput,decryptor,CryptoStreamMode.Write); for (long i = 0; i < fsInput.Length; i += chunkSize) { byte[] chunkData = new byte[chunkSize]; fsInput.Read(chunkData, 0, chunkSize); cryptoStream.Write(chunkData, 0, chunkData.Length); } cryptoStream.Close(); cryptoStream.Dispose(); fsInput.Close(); fsInput.Dispose(); } 

这对我来说“看起来很好”,但遗憾的是看起来似乎是在欺骗!

加密工作没有错误,但在解密期间,“cryptoStream.Close()”方法抛出以下exception:

System.Security.Cryptography.CryptographicException未处理Message =“填充无效,无法删除。”
Source =“mscorlib”StackTrace:在System.Security.Cryptography的System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte [] inputBuffer,Int32 inputOffset,Int32 inputCount,Byte []&outputBuffer,Int32 outputOffset,PaddingMode paddingMode,Boolean fLast) .RijndaelManagedTransform.TransformFinalBlock(Byte [] inputBuffer,Int32 inputOffset,Int32 inputCount)在System.Security.Cryptography.CryptoStream.FlushFinalBlock()处于System.Security.Cryptography.CryptoStream.Dispose(布局处理)System.IO.Stream.Close ()

看来未加密的文件大小与预期的文件大小不匹配(范围从大约8个字节到大约60个)

我通过改变RijndaelManaged对象创建行来“修复”exception以包含填充类型,如下所示:

 RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC,Padding=PaddingMode.None }; 

但文件大小仍然不匹配,可以预见,新近未加密的文件是胡扯!

我承认我现在已经超出了加密/解密的舒适区域,这可能是一个新手的错误 – 但我无法发现它!

任何有关解决此问题的帮助将不胜感激!

问题是我正在使用:

 passwordDB.GetBytes(256 / 8) 

在加密和解密方法中的RijndaelManaged对象的构造函数中,我没有在尝试解密之前重新初始化passwordDB对象。

解决方案是简单地在Enc和Dec方法的第一行中包含passwordDB对象的构造,如下所示:

  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.ANSIX923}; 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) { if (bytesRead != 16) { for (int x = bytesRead - 1; x < chunkSize; x++) { chunkData[x] = 0; } } cryptoStream.Write(chunkData, 0, chunkSize); } } cryptoStream.FlushFinalBlock(); } } } } 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.ANSIX923}; 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); } } } } } } 

知道它必须是一个男生错误:P

Stream.Read方法返回实际从流中读取的字节数。

您应该将此返回值用作下一行Write方法中的最后一个参数。

我的代码看起来像这样:

 byte[] chunkData = new byte[chunkSize]; var bytesRead = 0; while ((bytesRead = fsInput.Read(chunkData, 0, chunkSize)) > 0) { cryptoStream.Write(chunkData, 0, bytesRead); } 

有一个CryptoStream类来加密/解密Streams