I have a password-protected zip file, where the paths and filenames of each file are encrypted using PKWARE encryption.
The password is known and correct, and so is the encryption algorithm.
I also have sample plaintext, and an application (32-bit closed-source, optimized, no debug symbols) that can correctly decrypt the files.
Below is a sample of the partially decrypted file names, alongside some fully decrypted file names.
Below is a sample of the fully decrypted files, generated by the closed-source program.
As you can observe, for the majority of the files, the file names can be correctly decrypted. However, for a small set, I get partially decoded file names, and mojibake for the rest.
So my question is, why is this happening and what should I do to rectify it? I am confused because I was expecting 100% rubbish if my decryption implementation was wrong. Partially correct output was not really what I expected.
Note that each file name is independently decrypted, in other words, the decryption of the next file does not depend on the decryption of the previous file.
The decryption implementation is more or less the same as that is described here:
static uint32_t keys[3];
// CRC32_table is from zlib
uint32_t compute_crc32(uint32_t crc, char c) {
return CRC32_table[(crc ^ c) & 0xff] ^ (crc >> 8);
}
void init_keys(const std::string& password) {
keys = { 0x12345678, 0x23456789, 0x34567890 };
for (size_t i = 0; i < password.size(); ++i)
key_update(keys, password[i]);
}
void update_keys(char c) {
keys[0] = compute_crc32(keys[0], c);
keys[1] = keys[1] + (keys[0] & 0xff);
keys[1] = (keys[1] * 0x8088405) + 1;
keys[2] = compute_crc32(keys[2], keys[1] >> 24);
}
char decrypt_byte() {
uint16_t temp = (keys[2] & 0xffff) | 2;
return char(((temp * (temp ^ 1))>> 8) & 0xff);
}
std::string decrypt(const std::string& password,
const std::string& input) {
init_keys(password);
auto ret = std::string(input.size(), '\0');
for (int i = 0; i < input.size(); ++i) {
char c = input[i] ^ decrypt_byte();
update_keys(c);
ret[i] = c;
}
return ret;
}
Note that the files are still correctly decrypted and unzipped, it is only the file names that are scrambled.