From b94540426dd07324114a2b82905a6b92a696e73c Mon Sep 17 00:00:00 2001 From: Richard Webb Date: Mon, 18 Feb 2019 14:55:50 +0000 Subject: [PATCH 1/2] Fix ZipOutputStream.CloseEntry() to work for Stored AES encrypted entries --- .../Zip/Compression/Streams/DeflaterOutputStream.cs | 5 ++++- src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/DeflaterOutputStream.cs b/src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/DeflaterOutputStream.cs index f08947d0e..58bbc4c2d 100644 --- a/src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/DeflaterOutputStream.cs +++ b/src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/DeflaterOutputStream.cs @@ -414,7 +414,10 @@ protected override void Dispose(bool disposing) } } - private void GetAuthCodeIfAES() + /// + /// Get the Auth code for AES encrypted entries + /// + protected void GetAuthCodeIfAES() { if (cryptoTransform_ is ZipAESTransform) { diff --git a/src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs b/src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs index 88c810393..ab711d19b 100644 --- a/src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs +++ b/src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs @@ -486,6 +486,12 @@ public void CloseEntry() deflater_.Reset(); } } + else if (curMethod == CompressionMethod.Stored) + { + // This is done by Finsh() for Deflated entries, but we need to do it + // ourselves for Stored ones + base.GetAuthCodeIfAES(); + } // Write the AES Authentication Code (a hash of the compressed and encrypted data) if (curEntry.AESKeySize > 0) From 96c4e28926a49d4bfd65947efcd8effd77f2b794 Mon Sep 17 00:00:00 2001 From: Richard Webb Date: Mon, 18 Feb 2019 14:56:32 +0000 Subject: [PATCH 2/2] Add unit tests for AES encrypted zips whose contents are Stored rather than Deflated --- .../Zip/ZipEncryptionHandling.cs | 64 ++++++++++++++++++- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/test/ICSharpCode.SharpZipLib.Tests/Zip/ZipEncryptionHandling.cs b/test/ICSharpCode.SharpZipLib.Tests/Zip/ZipEncryptionHandling.cs index c805fa9b4..865965e0d 100644 --- a/test/ICSharpCode.SharpZipLib.Tests/Zip/ZipEncryptionHandling.cs +++ b/test/ICSharpCode.SharpZipLib.Tests/Zip/ZipEncryptionHandling.cs @@ -19,6 +19,14 @@ public void Aes128Encryption() CreateZipWithEncryptedEntries("foo", 128); } + [Test] + [Category("Encryption")] + [Category("Zip")] + public void Aes128EncryptionStored() + { + CreateZipWithEncryptedEntries("foo", 128, CompressionMethod.Stored); + } + [Test] [Category("Encryption")] [Category("Zip")] @@ -27,6 +35,14 @@ public void Aes256Encryption() CreateZipWithEncryptedEntries("foo", 256); } + [Test] + [Category("Encryption")] + [Category("Zip")] + public void Aes256EncryptionStored() + { + CreateZipWithEncryptedEntries("foo", 256, CompressionMethod.Stored); + } + [Test] [Category("Encryption")] [Category("Zip")] @@ -88,6 +104,47 @@ public void ZipFileAesRead() } } + /// + /// Test using AES encryption on a file whose contents are Stored rather than deflated + /// + [Test] + [Category("Encryption")] + [Category("Zip")] + public void ZipFileStoreAes() + { + string password = "password"; + + using (var memoryStream = new MemoryStream()) + { + // Try to create a zip stream + WriteEncryptedZipToStream(memoryStream, password, 256, CompressionMethod.Stored); + + // reset + memoryStream.Seek(0, SeekOrigin.Begin); + + // try to read it + var zipFile = new ZipFile(memoryStream, leaveOpen: true) + { + Password = password + }; + + foreach (ZipEntry entry in zipFile) + { + if (!entry.IsFile) continue; + + // Should be stored rather than deflated + Assert.That(entry.CompressionMethod, Is.EqualTo(CompressionMethod.Stored), "Entry should be stored"); + + using (var zis = zipFile.GetInputStream(entry)) + using (var sr = new StreamReader(zis, Encoding.UTF8)) + { + var content = sr.ReadToEnd(); + Assert.That(content, Is.EqualTo(DummyDataString), "Decompressed content does not match input data"); + } + } + } + } + private static readonly string[] possible7zPaths = new[] { // Check in PATH "7z", "7za", @@ -135,7 +192,7 @@ public static bool TryGet7zBinPath(out string path7z) return false; } - public void WriteEncryptedZipToStream(Stream stream, string password, int keySize) + public void WriteEncryptedZipToStream(Stream stream, string password, int keySize, CompressionMethod compressionMethod = CompressionMethod.Deflated) { using (var zs = new ZipOutputStream(stream)) { @@ -146,6 +203,7 @@ public void WriteEncryptedZipToStream(Stream stream, string password, int keySiz ZipEntry zipEntry = new ZipEntry("test"); zipEntry.AESKeySize = keySize; zipEntry.DateTime = DateTime.Now; + zipEntry.CompressionMethod = compressionMethod; zs.PutNextEntry(zipEntry); @@ -160,11 +218,11 @@ public void WriteEncryptedZipToStream(Stream stream, string password, int keySiz } } - public void CreateZipWithEncryptedEntries(string password, int keySize) + public void CreateZipWithEncryptedEntries(string password, int keySize, CompressionMethod compressionMethod = CompressionMethod.Deflated) { using (var ms = new MemoryStream()) { - WriteEncryptedZipToStream(ms, password, keySize); + WriteEncryptedZipToStream(ms, password, keySize, compressionMethod); if (TryGet7zBinPath(out string path7z)) {