diff --git a/lib/zip_source_crc.c b/lib/zip_source_crc.c index 9933dae4d..34966c2d5 100644 --- a/lib/zip_source_crc.c +++ b/lib/zip_source_crc.c @@ -152,11 +152,15 @@ static zip_int64_t crc_read(zip_source_t *src, void *_ctx, void *data, zip_uint6 /* TODO: Set comp_size, comp_method, encryption_method? After all, this only works for uncompressed data. */ st->size = ctx->size; - st->crc = ctx->crc; st->comp_size = ctx->size; st->comp_method = ZIP_CM_STORE; st->encryption_method = ZIP_EM_NONE; - st->valid |= ZIP_STAT_SIZE | ZIP_STAT_CRC | ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD | ZIP_STAT_ENCRYPTION_METHOD; + st->valid |= ZIP_STAT_SIZE | ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD | ZIP_STAT_ENCRYPTION_METHOD; + /* When validating, don't report a CRC for data that has none (WinZip AES AE-2). */ + if (!ctx->validate || (st->valid & ZIP_STAT_CRC)) { + st->crc = ctx->crc; + st->valid |= ZIP_STAT_CRC; + } } return 0; } diff --git a/lib/zip_source_zip_new.c b/lib/zip_source_zip_new.c index 8ed76964c..f36be6859 100644 --- a/lib/zip_source_zip_new.c +++ b/lib/zip_source_zip_new.c @@ -141,8 +141,8 @@ ZIP_EXTERN zip_source_t *zip_source_zip_file_create(zip_t *srcza, zip_uint64_t s needs_decrypt = ((flags & ZIP_FL_ENCRYPTED) == 0) && encrypted; compressed = (st.valid & ZIP_STAT_COMP_METHOD) && (st.comp_method != ZIP_CM_STORE); needs_decompress = ((flags & ZIP_FL_COMPRESSED) == 0) && compressed; - /* when reading the whole file, check for CRC errors */ - needs_crc = ((flags & ZIP_FL_COMPRESSED) == 0 || !compressed) && !partial_data && (st.valid & ZIP_STAT_CRC) != 0; + /* when reading the whole file, check for CRC errors; for decrypted data without CRC (WinZip AES AE-2), still check the length */ + needs_crc = ((flags & ZIP_FL_COMPRESSED) == 0 || !compressed) && !partial_data && ((st.valid & ZIP_STAT_CRC) != 0 || needs_decrypt); if (needs_decrypt) { if (password == NULL) { diff --git a/regress/data/incons-aes-ae2-data-longer.zip b/regress/data/incons-aes-ae2-data-longer.zip new file mode 100644 index 000000000..10cf9b5a6 Binary files /dev/null and b/regress/data/incons-aes-ae2-data-longer.zip differ diff --git a/regress/data/incons-aes-ae2-data-shorter.zip b/regress/data/incons-aes-ae2-data-shorter.zip new file mode 100644 index 000000000..c996c74da Binary files /dev/null and b/regress/data/incons-aes-ae2-data-shorter.zip differ diff --git a/regress/read_incons_aes_ae2_longer.test b/regress/read_incons_aes_ae2_longer.test new file mode 100644 index 000000000..a5595e6d0 --- /dev/null +++ b/regress/read_incons_aes_ae2_longer.test @@ -0,0 +1,11 @@ +# WinZip AES AE-2 entry (no CRC) decrypts to more data than the uncompressed size in its header +features HAVE_CRYPTO +arguments test.zip set_password foofoofoo cat 1 +return 1 +file test.zip incons-aes-ae2-data-longer.zip +stdout +encrypted +end-of-inline-data +stderr +can't read file at index '1': Zip archive inconsistent: file length in header doesn't match actual file length +end-of-inline-data diff --git a/regress/read_incons_aes_ae2_shorter.test b/regress/read_incons_aes_ae2_shorter.test new file mode 100644 index 000000000..0fb84b447 --- /dev/null +++ b/regress/read_incons_aes_ae2_shorter.test @@ -0,0 +1,11 @@ +# WinZip AES AE-2 entry (no CRC) decrypts to less data than the uncompressed size in its header +features HAVE_CRYPTO +arguments test.zip set_password foofoofoo cat 1 +return 1 +file test.zip incons-aes-ae2-data-shorter.zip +stdout +encrypted +end-of-inline-data +stderr +can't read file at index '1': Zip archive inconsistent: file length in header doesn't match actual file length +end-of-inline-data