Skip to content

Commit

Permalink
Experiment with using ITaggedData for AES extra data handling
Browse files Browse the repository at this point in the history
  • Loading branch information
Numpsy committed May 30, 2020
1 parent f36ca37 commit 44da647
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 31 deletions.
21 changes: 8 additions & 13 deletions src/ICSharpCode.SharpZipLib/Zip/ZipEntry.cs
Expand Up @@ -1129,26 +1129,21 @@ private DateTime GetDateTime(ZipExtraData extraData)
//
private void ProcessAESExtraData(ZipExtraData extraData)
{
if (extraData.Find(0x9901))
var aesData = extraData.GetData<WinZipAESTaggedData>();

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");
}
}

/// <summary>
Expand Down
116 changes: 110 additions & 6 deletions src/ICSharpCode.SharpZipLib/Zip/ZipExtraData.cs
Expand Up @@ -14,7 +14,7 @@ public interface ITaggedData
/// <summary>
/// Get the ID for this tagged data value.
/// </summary>
short TagID { get; }
ushort TagID { get; }

/// <summary>
/// Set the contents of this instance from the data passed.
Expand All @@ -40,7 +40,7 @@ public class RawTaggedData : ITaggedData
/// Initialise a new instance.
/// </summary>
/// <param name="tag">The tag ID.</param>
public RawTaggedData(short tag)
public RawTaggedData(ushort tag)
{
_tag = tag;
}
Expand All @@ -50,7 +50,7 @@ public RawTaggedData(short tag)
/// <summary>
/// Get the ID for this tagged data value.
/// </summary>
public short TagID
public ushort TagID
{
get { return _tag; }
set { _tag = value; }
Expand Down Expand Up @@ -99,7 +99,7 @@ public byte[] Data
/// <summary>
/// The tag ID for this instance.
/// </summary>
private short _tag;
private ushort _tag;

private byte[] _data;

Expand Down Expand Up @@ -138,7 +138,7 @@ public enum Flags : byte
/// <summary>
/// Get the ID
/// </summary>
public short TagID
public ushort TagID
{
get { return 0x5455; }
}
Expand Down Expand Up @@ -327,7 +327,7 @@ public class NTTaggedData : ITaggedData
/// <summary>
/// Get the ID for this tagged data value.
/// </summary>
public short TagID
public ushort TagID
{
get { return 10; }
}
Expand Down Expand Up @@ -474,6 +474,110 @@ public DateTime LastAccessTime
#endregion Instance Fields
}

/// <summary>
/// A TaggedData for handling WinzipAES extra data.
/// </summary>
/// <remarks>
/// See http://www.winzip.com/aes_info.htm for format documentation.
/// </remarks>
internal class WinZipAESTaggedData : ITaggedData
{
/// <summary>
/// The Version used by this entry.
/// </summary>
/// <remarks>
/// AE-1 iS 1. AE-2 is 2. With AE-2 no CRC is required and 0 is stored.
/// </remarks>
public enum VendorVersion : int
{
/// <summary>
/// Version AE-1.
/// </summary>
AE1 = 0x0001,

/// <summary>
/// Version AE-2.
/// </summary>
AE2 = 0x0002,
}

/// <summary>
/// Get the ID for this tagged data value.
/// </summary>
public ushort TagID => 0x9901;

/// <summary>
/// Set the data from the raw values provided.
/// </summary>
/// <param name="data">The raw data to extract values from.</param>
/// <param name="index">The index to start extracting values from.</param>
/// <param name="count">The number of bytes available.</param>
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;
}
}

/// <summary>
/// Get the binary data representing this instance.
/// </summary>
/// <returns>The raw binary data representing this instance.</returns>
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();
}
}

/// <summary>
/// Get/set the <see cref="VendorVersion"> for this entry.</see>
/// </summary>
/// <remarks>
/// Defaults to 2 because we always use that when encrypting new entries.
/// </remarks>
public VendorVersion Version { get; set; } = VendorVersion.AE2;

/// <summary>
/// Get /set the real <see cref="CompressionMethod"> for this entry.</see>.
/// </summary>
public CompressionMethod CompressionMethod { get; set; }

/// <summary>
/// Get /set the encryption strength for this entry - 1 = 128 bit, 2 = 192 bit, 3 = 256 bit
/// </summary>
public byte EncryptionStrength { get; set; }
}

/// <summary>
/// A factory that creates <see cref="ITaggedData">tagged data</see> instances.
/// </summary>
Expand Down
19 changes: 7 additions & 12 deletions src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs
Expand Up @@ -609,18 +609,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
Expand Down

0 comments on commit 44da647

Please sign in to comment.