1
$\begingroup$

I'm trying to write a function in dart that can can decrypt a file inside a zip that is encrypted using the WinZip AES-256 standard. Documentation I have found here: https://www.winzip.com/en/support/aes-encryption/. Using 7-Zip I was able to create an example file according to the standard. I'm able to extract the encryption key and the cipher text according to the spec:

encryptionKey: 9f2df21ad65ff7f33b817c5686042f1dc038f0290cbe0189f2ee2bb610bf033d
cipherText: f88a3bd439b4aef91ebaa9
expected: 68656c6c6f20776f726c64 (hello world)
output: c5e7de168b7dd6f3b157d4

Any tool or package that I use is not able to decrypt it in to the right message. So I looked at a nodejs library that used a special implementation for decrypting that does not seem to be exactly equal to standard AES. It is called a Gladmann specific implementation. as you can see here: https://github.com/gildas-lormeau/zip.js/blob/master/lib/core/codecs/sjcl.js#L590

I've downloaded this nodejs package and was able to confirm that my input data was valid so my question is why are there multiple implementations of AES? And what would be the best approach to implement this in dart?

I could try to mimic the same logic in dart which is duable but challenging. Would it be possible to leverage an existing library and make a small change to make it work? If so what would that change be?

Unfortunately documentation on the internet regarding the WinZip AES sepcification are scarce. The only other lead I could find was the implementation from the Brian Gladmann him self: https://github.com/BrianGladman/aes but it lacks documentation and goes a little above my knowledge.

Thanks for the help :)

$\endgroup$
1
1
$\begingroup$

I'll assume that you have already performed PBKDF2 with the static 1000 iterations defined (which is, uh, on the low end of security), and that the two key check bytes have been validated.

AES itself is no different, and it seems that Winzip doesn't use anything special. The only thing that is a bit weird is that the counter is in little endian. This is all C-code, so endianness is defined by the platform, and mostly that means little endian.

Nothing prohibits the use of a little endian counter for CTR mode, but in 99% of the cases it'll be big endian. You may need to implement CTR-LE yourself on top of the AES cipher (or AES-ECB, which is kind of the same).

Also note that the ZIP - uh - standard defines an encrypted header, so the start of the decrypted plaintext won't be the file contents.

Similarly, the authentication tag is just HMAC-SHA1-80 over the ciphertext. HMAC-SHA1-80 is just HMAC-SHA-1 of which only 80 bits are used, i.e. half of the output size of HMAC-SHA-1, usually the leftmost bits.

If you're stuck, I'd take a careful look at the code to check if you don't have any values backwards (e.g. maybe it uses the rightmost bytes of the HMAC, unlikely, but yeah).

$\endgroup$
1
  • 1
    $\begingroup$ The fact that WinZip 11 and higher stores the CRC32 over the plaintext for any file > 20 bytes just takes the cake. "Because for some very small files the CRC can be used to determine the exact contents of a file". No, you idiots, you can determine with high certainty that a file contains specific data, regardless of size. If you want to encrypt anything then don't use WinZip for that. $\endgroup$
    – Maarten Bodewes
    Sep 14 at 20:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.