-
Notifications
You must be signed in to change notification settings - Fork 976
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AES decryption support in ZipInputStream #551
base: master
Are you sure you want to change the base?
Conversation
One of the issues here is the way that the inflator input machinery works by trying to consume all the input so that it can work in cases where it doesn't know the length of the data in advance (i.e. when reading a Zip entry with a descriptor). I've thought in the past that it could be changed to use the compressed size fields in cases where they're known, but that would be a more generic change and not encryption specific. Saying that - just being able to decrypt entries that don't use a descriptor is still a benefit, just needs a few extra checks to make sure things like CanDecompress give the correct values. (/not particularly a fan of more zip specific encryption code in the inflator, but that's how it works so, !) |
I don't quite get what situation you are refering to. To my understanding the Zip specification ensures that a Zip entry always comes with a header that specifies the compressed size. The |
Not quite - there are two modes of operation for entries - one which puts the sizes in the file header, and one which sets the header values to 0 and puts the sizes in a |
Ok got it. That use case is now covered and tested as well.
The only way I could create such a file that has both AES encryption and data descriptor was using SharpZipLib itself. |
Well, the reason is that Descriptors are used for streaming data, where you might not know the file size before hand, or you cannot modify the stream to update the header (like with a web server response). This scenario doesn't really make sense with a file-based stand-alone executable. Perhaps for a CLI version that pipes to stdout, not sure if 7z CLI might do it perhaps? |
test/ICSharpCode.SharpZipLib.Tests/Zip/ZipEncryptionHandling.cs
Outdated
Show resolved
Hide resolved
Ready for review |
I'll try to have a look later
I've seen document files created by LibreOffice (using the file formats that use zip file containers) that use descriptors, though probably not together with this form of encryption (just as an example of how these sort of files can come about through 'normal' file based tools) |
Did I ever query whether there would be any benefir of making use of the entry size (when known) in all cases, rather than just for AES entries (e.g. something like what DecryptionLimit does, but for plain compressed entries)? |
src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/InflaterInputStream.cs
Show resolved
Hide resolved
(I still need to have a more detailed read over the other logic in the nexzt day or two) |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #551 +/- ##
==========================================
+ Coverage 74.70% 74.92% +0.21%
==========================================
Files 72 72
Lines 8465 8533 +68
==========================================
+ Hits 6324 6393 +69
+ Misses 2141 2140 -1 ☔ View full report in Codecov by Sentry. |
It doesn't matter how these entries can be created with other libraries. It is possible to create them with SharpZipLib. And there is a test to verify these entries can be unzipped and decrypted. |
Is there any update for this pull request? |
Sorry, I haven't had much spare time to do things lately, I'll have another look over the weekend |
Is that last change a separate bug fix for ZipOutputStream? |
Yes and No It's a separate bugfix for the ZipOutputStream. But due to that bug it is not possible to create certain zip files needed fo the unit tests of this pull request. |
Regarding The specification says that the CRC should be set to 0, but only for AE-2 and explicitly states that
And I think that
should be interpreted as "when reading, ignore the Zip CRC", it shouldn't refuse to read it. |
Seems I had the issue not correctly in mind anymore. The problem is not that the tests fail. But that the tests do not test what they are supposed to test. There are multiple use cases that need to be tested. AES decryption needs to be able to handle both cases the one where there is a data descrpytor and the one where there isn't one. This is done by one tests that used InlineData to test the different variations.
The thing is here that the parameter forceDataDescriptor is basically meaningless if the ZipOutputStream always adds one anyways in case there is a password. With the unchanged ZipOutputStream it is only possible to test the cases where there is a data descryptor as only such files can be created by it. All the cases where there isn't a data desscryptor can't be tested otherwise. With my second last change I fixed a bug that lead to an exception in case an entry was only read partially and not until the end of the stream. If you undo these changes (only the ZipInputStream not the tests) and the changes to the ZipOutputStream you will notice that only the test case that "stores" entries will fail. The test case that "deflate" the entries will pass successfully which is not what is expected. But if you change the ZipOutputStream so that there is no data descryptor when it is not needed it will fail as expected. By the way, tools like 7-Zip are also not adding a data descryptor in this case. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, not adding it when not needed is indeed the right thing to do, I just questioned not allowing them to be there.
I think I understand what happened, but my internal zip emulation is at its limits 😁.
Just a note on the test arguments...
test/ICSharpCode.SharpZipLib.Tests/Zip/ZipEncryptionHandling.cs
Outdated
Show resolved
Hide resolved
test/ICSharpCode.SharpZipLib.Tests/Zip/ZipEncryptionHandling.cs
Outdated
Show resolved
Hide resolved
test/ICSharpCode.SharpZipLib.Tests/Zip/ZipEncryptionHandling.cs
Outdated
Show resolved
Hide resolved
test/ICSharpCode.SharpZipLib.Tests/Zip/ZipEncryptionHandling.cs
Outdated
Show resolved
Hide resolved
test/ICSharpCode.SharpZipLib.Tests/Zip/ZipEncryptionHandling.cs
Outdated
Show resolved
Hide resolved
src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/InflaterInputStream.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I get how it works now, more or less. These where just some thoughts when trying to follow the exciting journey of DecryptionLimit
.
src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/InflaterInputStream.cs
Outdated
Show resolved
Hide resolved
Hi, any updates? |
769b6b3
to
5972bae
Compare
Hi @piksel, is there any chance you could review the changes from @remogloor anytime soon? We would be very happy to have this feature in the library. |
This pull request continues the work of @Numpsy and replaces Pull Request #381
The issue with the HMAC calculation in the original pull request was that it always decrypted and calculated HMAC for the entire input buffer. But actually it should only decrypt and calculate the HMAC up to the compressed size of the current entry. This issue is fixed now and all the unit tests pass. AES encrypted Zips can now be decrypted and decompressed using the ZipInput Stream.
Original Information from #381
I certify that I own, and have sufficient rights to contribute, all source code and related material intended to be compiled or integrated with the source code for the SharpZipLib open source product (the "Contribution"). My Contribution is licensed under the MIT License.