diff --git a/src/ICSharpCode.SharpZipLib/Zip/ZipEntry.cs b/src/ICSharpCode.SharpZipLib/Zip/ZipEntry.cs index ffeee1883..975bc5e5c 100644 --- a/src/ICSharpCode.SharpZipLib/Zip/ZipEntry.cs +++ b/src/ICSharpCode.SharpZipLib/Zip/ZipEntry.cs @@ -962,26 +962,21 @@ internal void ProcessExtraData(bool localHeader) // For AES the method in the entry is 99, and the real compression method is in the extradata private void ProcessAESExtraData(ZipExtraData extraData) { - if (extraData.Find(0x9901)) + var aesData = extraData.GetData(); + + if (aesData != null) { // Set version for Zipfile.CreateAndInitDecryptionStream versionToExtract = ZipConstants.VERSION_AES; // Ver 5.1 = AES see "Version" getter - // - // Unpack AES extra data field see http://www.winzip.com/aes_info.htm - int length = extraData.ValueLength; // Data size currently 7 - if (length < 7) - throw new ZipException("AES Extra Data Length " + length + " invalid."); - int ver = extraData.ReadShort(); // Version number (1=AE-1 2=AE-2) - int vendorId = extraData.ReadShort(); // 2-character vendor ID 0x4541 = "AE" - int encrStrength = extraData.ReadByte(); // encryption strength 1 = 128 2 = 192 3 = 256 - int actualCompress = extraData.ReadShort(); // The actual compression method used to compress the file - _aesVer = ver; - _aesEncryptionStrength = encrStrength; - method = (CompressionMethod)actualCompress; + _aesVer = (int)aesData.Version; + _aesEncryptionStrength = aesData.EncryptionStrength; + method = aesData.CompressionMethod; } else + { throw new ZipException("AES Extra Data missing"); + } } /// diff --git a/src/ICSharpCode.SharpZipLib/Zip/ZipExtraData.cs b/src/ICSharpCode.SharpZipLib/Zip/ZipExtraData.cs index 4e075dc8d..4e8d24271 100644 --- a/src/ICSharpCode.SharpZipLib/Zip/ZipExtraData.cs +++ b/src/ICSharpCode.SharpZipLib/Zip/ZipExtraData.cs @@ -15,7 +15,7 @@ public interface ITaggedData /// /// Get the ID for this tagged data value. /// - short TagID { get; } + ushort TagID { get; } /// /// Set the contents of this instance from the data passed. @@ -41,7 +41,7 @@ public class RawTaggedData : ITaggedData /// Initialise a new instance. /// /// The tag ID. - public RawTaggedData(short tag) + public RawTaggedData(ushort tag) { _tag = tag; } @@ -51,7 +51,7 @@ public RawTaggedData(short tag) /// /// Get the ID for this tagged data value. /// - public short TagID + public ushort TagID { get { return _tag; } set { _tag = value; } @@ -100,7 +100,7 @@ public byte[] Data /// /// The tag ID for this instance. /// - private short _tag; + private ushort _tag; private byte[] _data; @@ -139,7 +139,7 @@ public enum Flags : byte /// /// Get the ID /// - public short TagID + public ushort TagID { get { return 0x5455; } } @@ -328,7 +328,7 @@ public class NTTaggedData : ITaggedData /// /// Get the ID for this tagged data value. /// - public short TagID + public ushort TagID { get { return 10; } } @@ -475,6 +475,110 @@ public DateTime LastAccessTime #endregion Instance Fields } + /// + /// A TaggedData for handling WinzipAES extra data. + /// + /// + /// See http://www.winzip.com/aes_info.htm for format documentation. + /// + internal class WinZipAESTaggedData : ITaggedData + { + /// + /// The Version used by this entry. + /// + /// + /// AE-1 iS 1. AE-2 is 2. With AE-2 no CRC is required and 0 is stored. + /// + public enum VendorVersion : int + { + /// + /// Version AE-1. + /// + AE1 = 0x0001, + + /// + /// Version AE-2. + /// + AE2 = 0x0002, + } + + /// + /// Get the ID for this tagged data value. + /// + public ushort TagID => 0x9901; + + /// + /// Set the data from the raw values provided. + /// + /// The raw data to extract values from. + /// The index to start extracting values from. + /// The number of bytes available. + public void SetData(byte[] data, int index, int count) + { + using (MemoryStream ms = new MemoryStream(data, index, count, false)) + using (ZipHelperStream helperStream = new ZipHelperStream(ms)) + { + // + // Unpack AES extra data field see http://www.winzip.com/aes_info.htm + var length = helperStream.Length; // Data size currently 7 + if (length < 7) + throw new ZipException("AES Extra Data Length " + length + " invalid."); + + int ver = helperStream.ReadLEShort(); // Version number (1=AE-1 2=AE-2) + int vendorId = helperStream.ReadLEShort(); // 2-character vendor ID 0x4541 = "AE" + int encrStrength = helperStream.ReadByte(); // encryption strength 1 = 128 2 = 192 3 = 256 + int actualCompress = helperStream.ReadLEShort(); // The actual compression method used to compress the file + + this.Version = (VendorVersion)ver; + this.EncryptionStrength = (byte)encrStrength; + this.CompressionMethod = (CompressionMethod)actualCompress; + } + } + + /// + /// Get the binary data representing this instance. + /// + /// The raw binary data representing this instance. + public byte[] GetData() + { + using (MemoryStream ms = new MemoryStream()) + using (ZipHelperStream helperStream = new ZipHelperStream(ms)) + { + helperStream.IsStreamOwner = false; + + // Vendor ID is the two ASCII characters "AE". + const int VENDOR_ID = 0x4541; //not 6965; + + // Pack AES extra data field see http://www.winzip.com/aes_info.htm + // extraData.AddLeShort(7); // Data size (currently 7) + helperStream.WriteLEShort((int)this.Version); // Entry version + helperStream.WriteLEShort(VENDOR_ID); // "AE" + helperStream.WriteByte(this.EncryptionStrength); // 1 = 128, 2 = 192, 3 = 256 + helperStream.WriteLEShort((int)this.CompressionMethod); // The actual compression method used to compress the file + + return ms.ToArray(); + } + } + + /// + /// Get/set the for this entry. + /// + /// + /// Defaults to 2 because we always use that when encrypting new entries. + /// + public VendorVersion Version { get; set; } = VendorVersion.AE2; + + /// + /// Get /set the real for this entry.. + /// + public CompressionMethod CompressionMethod { get; set; } + + /// + /// Get /set the encryption strength for this entry - 1 = 128 bit, 2 = 192 bit, 3 = 256 bit + /// + public byte EncryptionStrength { get; set; } + } + /// /// A factory that creates tagged data instances. /// diff --git a/src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs b/src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs index 79d65f560..b72cf8529 100644 --- a/src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs +++ b/src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs @@ -706,18 +706,13 @@ private void WriteEncryptionHeader(long crcValue) private static void AddExtraDataAES(ZipEntry entry, ZipExtraData extraData) { - // Vendor Version: AE-1 IS 1. AE-2 is 2. With AE-2 no CRC is required and 0 is stored. - const int VENDOR_VERSION = 2; - // Vendor ID is the two ASCII characters "AE". - const int VENDOR_ID = 0x4541; //not 6965; - extraData.StartNewEntry(); - // Pack AES extra data field see http://www.winzip.com/aes_info.htm - //extraData.AddLeShort(7); // Data size (currently 7) - extraData.AddLeShort(VENDOR_VERSION); // 2 = AE-2 - extraData.AddLeShort(VENDOR_ID); // "AE" - extraData.AddData(entry.AESEncryptionStrength); // 1 = 128, 2 = 192, 3 = 256 - extraData.AddLeShort((int)entry.CompressionMethod); // The actual compression method used to compress the file - extraData.AddNewEntry(0x9901); + var aesData = new WinZipAESTaggedData + { + CompressionMethod = entry.CompressionMethod, + EncryptionStrength = entry.AESEncryptionStrength, + }; + + extraData.AddEntry(aesData); } // Replaces WriteEncryptionHeader for AES