我注意到一种我无法控制的奇怪行为。 Zip文件正在加密如下:
private static void EncryptFile(string source, string destination, string password, int iteration)
{
var keyGenerator = new Rfc2898DeriveBytes(password, 1000, iteration);
using (var aes = new RijndaelManaged
{
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7,
KeySize = 128,
BlockSize = 128
})
{
aes.Key = keyGenerator.GetBytes(16);
aes.IV = keyGenerator.GetBytes(16);
using (var sourceStream = File.OpenRead(source))
{
using (var destinationStream = File.OpenWrite(destination))
{
using (var cs = new CryptoStream(destinationStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
//salt (uncrypted)
destinationStream.Write(keyGenerator.Salt, 0, keyGenerator.Salt.Length);
//rest (crypted)
sourceStream.CopyTo(cs);
}
}
}
}
}
此方法将动态解密和解压缩文件。
private static void UnzipDecryptFile(string source, string destination, string password, int iteration)
{
using (var aes = new RijndaelManaged
{
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7,
KeySize = 128,
BlockSize = 128
})
{
using (var sourceStream = File.OpenRead(source))
{
var salt = new byte[1000];
sourceStream.Read(salt, 0, 1000);
var keyGenerator = new Rfc2898DeriveBytes(password, salt, iteration);
aes.Key = keyGenerator.GetBytes(16);
aes.IV = keyGenerator.GetBytes(16);
using (var cs = new CryptoStream(sourceStream, aes.CreateDecryptor(), CryptoStreamMode.Read))
{
using (var zipStream = new ZipInputStream(cs))
{
ZipEntry entry;
while ((entry = zipStream.GetNextEntry()) != null)
{
var c = entry.DateTime;
//do stuff with entry
}
}
}
}
}
}
不幸的是我无法使用System.IO.Compression.ZipArchive(Stream stream),因为如果流不支持 CanSeek ,它会将整个流复制到内存,哪个CryptoStream没有。
在最后一次调用zipStream.GetNextEntry()时,我收到一个CryptographicException:填充无效,无法删除。
at System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast)
at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
at System.Security.Cryptography.CryptoStream.FlushFinalBlock()
at System.Security.Cryptography.CryptoStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputStream.Close()
at ICSharpCode.SharpZipLib.Zip.ZipInputStream.Close()
at ICSharpCode.SharpZipLib.Zip.ZipInputStream.GetNextEntry()
GetNextEntry() will cause close on stream
这似乎是正确的行为。 ZipInputstream.GetNextEntry()没有找到下一个条目,因此它会关闭所有内容。
由于某些原因,CryptoStream.Dispose()方法认为它应该调用 FlushFinalBlock()但是因为所有内容都已经解密,所以它会失败。
如果我使用 PaddingMode.Zeros 而不是 PadddingMode.PKCS7 它会起作用,但这不是一个选项,因为这种模式在java中不可用(默认情况下将生成zip文件的那一方)。
我错过了什么?
[编辑] 对我来说更精确:解密/解包工作正常。在最后一次调用 zipStream.GetNextEntry()之后处理期间发生错误。对于一些Zip文件,根本不会发生错误。这可能是大小为16(块大小)的文件,不需要填充。