Skip to content

Commit bf4372a

Browse files
authored
PR #460: Account for AES overhead in compressed entry size (#460)
* Unit test for writing encrypted 0 byte files to ZipOutputStream * In ZipOutputStream.PutNextEntry, account for AES overhead when calculating compressed entry size
1 parent 3835f0c commit bf4372a

File tree

3 files changed

+60
-11
lines changed

3 files changed

+60
-11
lines changed

src/ICSharpCode.SharpZipLib/Zip/ZipEntry.cs

+21-1
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ public bool LocalHeaderRequiresZip64
655655

656656
if ((versionToExtract == 0) && IsCrypted)
657657
{
658-
trueCompressedSize += ZipConstants.CryptoHeaderSize;
658+
trueCompressedSize += (ulong)this.EncryptionOverheadSize;
659659
}
660660

661661
// TODO: A better estimation of the true limit based on compression overhead should be used
@@ -1013,6 +1013,26 @@ internal int AESOverheadSize
10131013
}
10141014
}
10151015

1016+
/// <summary>
1017+
/// Number of extra bytes required to hold the encryption header fields.
1018+
/// </summary>
1019+
internal int EncryptionOverheadSize
1020+
{
1021+
get
1022+
{
1023+
// Entry is not encrypted - no overhead
1024+
if (!this.IsCrypted)
1025+
return 0;
1026+
1027+
// Entry is encrypted using ZipCrypto
1028+
if (_aesEncryptionStrength == 0)
1029+
return ZipConstants.CryptoHeaderSize;
1030+
1031+
// Entry is encrypted using AES
1032+
return this.AESOverheadSize;
1033+
}
1034+
}
1035+
10161036
/// <summary>
10171037
/// Process extra data fields updating the entry based on the contents.
10181038
/// </summary>

src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs

+3-10
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ public void PutNextEntry(ZipEntry entry)
337337
}
338338
else
339339
{
340-
WriteLeInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CryptoHeaderSize : (int)entry.CompressedSize);
340+
WriteLeInt((int)entry.CompressedSize + entry.EncryptionOverheadSize);
341341
WriteLeInt((int)entry.Size);
342342
}
343343
}
@@ -382,7 +382,7 @@ public void PutNextEntry(ZipEntry entry)
382382
if (headerInfoAvailable)
383383
{
384384
ed.AddLeLong(entry.Size);
385-
ed.AddLeLong(entry.CompressedSize);
385+
ed.AddLeLong(entry.CompressedSize + entry.EncryptionOverheadSize);
386386
}
387387
else
388388
{
@@ -540,14 +540,7 @@ public void CloseEntry()
540540

541541
if (curEntry.IsCrypted)
542542
{
543-
if (curEntry.AESKeySize > 0)
544-
{
545-
curEntry.CompressedSize += curEntry.AESOverheadSize;
546-
}
547-
else
548-
{
549-
curEntry.CompressedSize += ZipConstants.CryptoHeaderSize;
550-
}
543+
curEntry.CompressedSize += curEntry.EncryptionOverheadSize;
551544
}
552545

553546
// Patch the header if possible

test/ICSharpCode.SharpZipLib.Tests/Zip/ZipEncryptionHandling.cs

+36
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,42 @@ public void ZipCryptoEncryption(CompressionMethod compressionMethod)
4242
CreateZipWithEncryptedEntries("foo", 0, compressionMethod);
4343
}
4444

45+
/// <summary>
46+
/// Test Known zero length encrypted entries with ZipOutputStream.
47+
/// These are entries where the entry size is set to 0 ahead of time, so that PutNextEntry will fill in the header and there will be no patching.
48+
/// Test with Zip64 on and off, as the logic is different for the two.
49+
/// </summary>
50+
[Test]
51+
public void ZipOutputStreamEncryptEmptyEntries(
52+
[Values] UseZip64 useZip64,
53+
[Values(0, 128, 256)] int keySize,
54+
[Values(CompressionMethod.Stored, CompressionMethod.Deflated)] CompressionMethod compressionMethod)
55+
{
56+
using (var ms = new MemoryStream())
57+
{
58+
using (var zipOutputStream = new ZipOutputStream(ms))
59+
{
60+
zipOutputStream.IsStreamOwner = false;
61+
zipOutputStream.Password = "password";
62+
zipOutputStream.UseZip64 = useZip64;
63+
64+
ZipEntry zipEntry = new ZipEntry("emptyEntry")
65+
{
66+
AESKeySize = keySize,
67+
CompressionMethod = compressionMethod,
68+
CompressedSize = 0,
69+
Crc = 0,
70+
Size = 0,
71+
};
72+
73+
zipOutputStream.PutNextEntry(zipEntry);
74+
zipOutputStream.CloseEntry();
75+
}
76+
77+
VerifyZipWith7Zip(ms, "password");
78+
}
79+
}
80+
4581
[Test]
4682
[Category("Encryption")]
4783
[Category("Zip")]

0 commit comments

Comments
 (0)