Skip to content

Comments

Fix CompressionType for WinZip AES encrypted ZIP entries#1213

Merged
adamhathcock merged 5 commits intomasterfrom
copilot/fix-compression-type-entry
Feb 12, 2026
Merged

Fix CompressionType for WinZip AES encrypted ZIP entries#1213
adamhathcock merged 5 commits intomasterfrom
copilot/fix-compression-type-entry

Conversation

Copy link
Contributor

Copilot AI commented Feb 12, 2026

WinZip AES encrypted entries report CompressionType.Unknown instead of the actual compression method (Deflate, LZMA, etc.). This is because WinZip AES stores the compression method in extra data at offset 5, not in the standard header field (which contains marker 0x63).

Changes

  • ZipEntry.cs: Added GetActualCompressionMethod() to extract compression method from WinZip AES extra data when present
  • Test updates: Changed tests that previously expected Unknown to assert the actual compression type

Technical Details

WinZip AES extra data structure (7+ bytes):

  • Bytes 0-1: Vendor version
  • Bytes 2-3: Vendor ID
  • Byte 4: AES strength
  • Bytes 5-6: Actual compression method ← extracted here

For non-WinZip AES entries, behavior is unchanged.

Example

// Before: WinZip AES encrypted entry
entry.CompressionType  // Returns: Unknown

// After: WinZip AES encrypted entry  
entry.CompressionType  // Returns: Deflate (or LZMA, etc.)
Original prompt

This section details on the original issue you should resolve

<issue_title>Compressiontype per entry when encrypted</issue_title>
<issue_description>Hello,

I made a encrypted archive with password and Deflate.
When i open the archive i see each entry.CompressionType = Unknown.
I open the same zip in 7zip it shows me the Deflate value.

is there a way to get this?</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 4 commits February 12, 2026 15:40
… Unknown

Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com>
Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com>
Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com>
Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix compression type visibility for encrypted entries Fix CompressionType for WinZip AES encrypted ZIP entries Feb 12, 2026
Copilot AI requested a review from adamhathcock February 12, 2026 15:52
@adamhathcock adamhathcock marked this pull request as ready for review February 12, 2026 16:27
Copilot AI review requested due to automatic review settings February 12, 2026 16:27
@kiloconnect
Copy link
Contributor

kiloconnect bot commented Feb 12, 2026

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (4 files)
  • src/SharpCompress/Common/Zip/ZipEntry.cs
  • tests/SharpCompress.Test/Zip/ZipArchiveTests.cs
  • tests/SharpCompress.Test/Zip/ZipReaderAsyncTests.cs
  • tests/SharpCompress.Test/Zip/ZipReaderTests.cs

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates ZIP entry metadata handling so WinZip AES–encrypted ZIP entries report their actual compression type (e.g., Deflate/LZMA) based on AES extra data, aligning Entry.CompressionType with how extraction already determines the real method.

Changes:

  • Add WinZip AES extra-field parsing in ZipEntry to derive the actual compression method for CompressionType.
  • Update existing WinZip AES reader tests to assert the real compression type instead of Unknown.
  • Add archive-level tests asserting CompressionType for WinZip AES and PKWARE encrypted ZIPs.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
src/SharpCompress/Common/Zip/ZipEntry.cs Derives CompressionType from WinZip AES extra data when the header method is WinzipAes (0x63).
tests/SharpCompress.Test/Zip/ZipReaderTests.cs Updates WinZip AES reader test expectations from Unknown to LZMA/Deflate.
tests/SharpCompress.Test/Zip/ZipReaderAsyncTests.cs Async equivalents of the WinZip AES test expectation updates.
tests/SharpCompress.Test/Zip/ZipArchiveTests.cs Adds new tests validating CompressionType for WinZip AES and PKWARE encrypted entries.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +67 to +70
if (_filePart?.Header.CompressionMethod != ZipCompressionMethod.WinzipAes)
{
ZipCompressionMethod.BZip2 => CompressionType.BZip2,
ZipCompressionMethod.Deflate => CompressionType.Deflate,
ZipCompressionMethod.Deflate64 => CompressionType.Deflate64,
ZipCompressionMethod.LZMA => CompressionType.LZMA,
ZipCompressionMethod.PPMd => CompressionType.PPMd,
ZipCompressionMethod.None => CompressionType.None,
ZipCompressionMethod.Shrink => CompressionType.Shrink,
ZipCompressionMethod.Reduce1 => CompressionType.Reduce1,
ZipCompressionMethod.Reduce2 => CompressionType.Reduce2,
ZipCompressionMethod.Reduce3 => CompressionType.Reduce3,
ZipCompressionMethod.Reduce4 => CompressionType.Reduce4,
ZipCompressionMethod.Explode => CompressionType.Explode,
ZipCompressionMethod.ZStandard => CompressionType.ZStandard,
_ => CompressionType.Unknown,
};
return _filePart?.Header.CompressionMethod ?? ZipCompressionMethod.None;
}
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetActualCompressionMethod() returns ZipCompressionMethod.None when _filePart is null, which changes the previous behavior of reporting CompressionType.Unknown in that case (old code switched on _filePart?.Header.CompressionMethod). If a ZipEntry can ever be constructed without a ZipFilePart, consider returning ZipCompressionMethod.WinzipAes/None only when you can prove the method, otherwise keep the prior Unknown behavior (e.g., return a sentinel that maps to CompressionType.Unknown).

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +86
// For WinZip AES, the actual compression method is stored in the extra data
var aesExtraData = _filePart.Header.Extra.FirstOrDefault(x =>
x.Type == ExtraDataType.WinZipAes
);

if (aesExtraData is null || aesExtraData.DataBytes.Length < MinimumWinZipAesExtraDataLength)
{
return ZipCompressionMethod.WinzipAes;
}

// The compression method is at offset 5 in the extra data
return (ZipCompressionMethod)
System.Buffers.Binary.BinaryPrimitives.ReadUInt16LittleEndian(
aesExtraData.DataBytes.AsSpan(WinZipAesCompressionMethodOffset)
);
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For WinZip AES entries, this reads the compression method from the extra field but does not validate the extra data (length == 7, vendor version, vendor ID) and it uses FirstOrDefault rather than SingleOrDefault. This can make Entry.CompressionType disagree with extraction behavior, since ZipFilePart.CreateDecompressionStream validates these fields and will throw on malformed or duplicate AES extra data. To keep behavior consistent, mirror the same validation and selection logic here and fall back to Unknown when the AES metadata is invalid.

Suggested change
// For WinZip AES, the actual compression method is stored in the extra data
var aesExtraData = _filePart.Header.Extra.FirstOrDefault(x =>
x.Type == ExtraDataType.WinZipAes
);
if (aesExtraData is null || aesExtraData.DataBytes.Length < MinimumWinZipAesExtraDataLength)
{
return ZipCompressionMethod.WinzipAes;
}
// The compression method is at offset 5 in the extra data
return (ZipCompressionMethod)
System.Buffers.Binary.BinaryPrimitives.ReadUInt16LittleEndian(
aesExtraData.DataBytes.AsSpan(WinZipAesCompressionMethodOffset)
);
// For WinZip AES, the actual compression method is stored in the extra data.
// Mirror the validation logic used during extraction so that behavior is consistent.
var aesExtraDataList = _filePart.Header.Extra
.Where(x => x.Type == ExtraDataType.WinZipAes)
.ToList();
// If there is not exactly one AES extra data record, treat the metadata as invalid.
if (aesExtraDataList.Count != 1)
{
// We do not know the actual compression method; keep WinzipAes so higher layers
// can treat the compression type as unknown.
return ZipCompressionMethod.WinzipAes;
}
var aesExtraData = aesExtraDataList[0];
var data = aesExtraData.DataBytes;
// WinZip AES extra data layout (7 bytes total):
// 0-1: Vendor version (1 or 2)
// 2-3: Vendor ID ("AE" -> 0x4541 little-endian)
// 4 : AES strength (ignored here)
// 5-6: Actual compression method
if (data is null || data.Length != MinimumWinZipAesExtraDataLength)
{
return ZipCompressionMethod.WinzipAes;
}
var span = data.AsSpan();
ushort vendorVersion =
System.Buffers.Binary.BinaryPrimitives.ReadUInt16LittleEndian(span.Slice(0, 2));
ushort vendorId =
System.Buffers.Binary.BinaryPrimitives.ReadUInt16LittleEndian(span.Slice(2, 2));
// Only accept known vendor versions and the WinZip AES vendor ID ("AE").
bool isSupportedVendorVersion = vendorVersion == 1 || vendorVersion == 2;
const ushort WinZipAesVendorId = 0x4541; // "AE" in little-endian
if (!isSupportedVendorVersion || vendorId != WinZipAesVendorId)
{
return ZipCompressionMethod.WinzipAes;
}
// The actual compression method is at offset 5 in the extra data.
ushort method =
System.Buffers.Binary.BinaryPrimitives.ReadUInt16LittleEndian(
span.Slice(WinZipAesCompressionMethodOffset, sizeof(ushort))
);
return (ZipCompressionMethod)method;

Copilot uses AI. Check for mistakes.
@adamhathcock adamhathcock merged commit 165239c into master Feb 12, 2026
12 checks passed
@adamhathcock adamhathcock deleted the copilot/fix-compression-type-entry branch February 12, 2026 16:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Compressiontype per entry when encrypted

2 participants