TZipFile with Password Encryption

As some of you might already know, Delphi (at least since XE2) comes with a built-in TZipFile class for reading and writing zip files. It is a rather basic class with only limited functionality, but this might just be enough for quite a couple of day-to-day tasks.

During a recent migration of a project from Delphi 7 to Delphi 10.1 Berlin I was facing the decision to either fix the current zip implementation (based on external DLLs) or switch to the stock implementation using TZipFile. The second option would also have the advantage of getting rid of distributing the DLLs. So I headed for that one.

Well, as always when you think you have found the right solution and start coding – reality steps in. Some of the zip files we had to read were password protected. Unfortunately TZipFile doesn’t support password encryption out of the box.

Getting rid of that external dependency was tempting and changing the non-encrypted use cases to use TZipFile was just breeze. Switching to another library (especially with evaluating the market first) seems like too much effort for so little gain. So I tinkered with the idea to implement the encryption part by myself. Honestly, how hard could it be?

Thankfully in this special scenario we only needed to read those encrypted zip files, so implementing the decryption part somehow would be sufficient. Investigating the available possibilities in TZipFile, I actually found instructions in the docs how to achieve this.

Actually TZipFile offers two kludges for that:

Both are class properties and such not tied to some instance of TZipFile. Instead they are valid for all TZipFile instances – similar to a global hook. We have to take this into account when using this properties in our implementation. Personally I would prefer a simple virtual method overriden by a derived class. The current class property approach can turn into a nightmare when it comes to multi-threading. I have no idea why the original developer actually choose to do it this way.

While the example in the docs is straight forward, I was looking for a more general case and went for a derived class hooking CreateDecompressStreamCallBack. The class TEncryptedZipFile is very light weight and merely introduces the Password property, which can also be initialized right with the constructor. The class constructor and destructor are responsible for hooking the CallBack. As that has to be persistent even outside any instantiation it is implemented as a class function.

The implementation resembles that of the example, while the real decryption work is delegated to a separate class TDecryptStream.

The implementation of TDecryptStream and the fact that it is derived from TBytesStream was heavily guided from one boundary condition specific to the expected use case: The zip files which are going to be decrypted are usually small and thus the whole decryption is done in memory directly inside the constructor.

The steps used for decryption are a straight forward implementation of the general steps described in https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT chapter 6.1, so I won’t go into the ugly details here. Here is the complete unit for download:  EncryptedZipFileRO

The next post will extend this with a more general approach that also allows writing password encrypted zip files.

About Uwe Raabe

Addicted to Pascal/Delphi since the late 70’s

This entry was posted in Delphi, Programming. Bookmark the permalink.

4 Responses to TZipFile with Password Encryption

  1. FLDelphi says:

    Great post, thank you Uwe. Looking forward to the encryption post.

  2. How hard would it be to add support for large (>3GB) archives?

  3. bugcheck says:

    The reason TZipFile doesn’t support encryptions is probably that the standard encryption is so weak it can only be considered obfuscation. IMO they made the right choice not to implement it.

    • Uwe Raabe says:

      The point here was that when I get an encrypted zip file I want to decrypt it. Weak encryption or not doesn’t matter in that case. The lack of possibility to attach any encryption out of the box prohibits the use of strong encryption as well.

Comments are closed.