Skip to content
1 change: 1 addition & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
<NoWarn>${NoWarn};IDE0051</NoWarn>
</PropertyGroup>
</Project>
47 changes: 13 additions & 34 deletions src/SharpCompress/Common/Zip/WinzipAesCryptoStream.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,55 +86,34 @@ public override async ValueTask<int> ReadAsync(
private void ReadTransformBlocks(Span<byte> buffer, int count)
{
var posn = 0;
var last = count;
var remaining = count;

while (posn < buffer.Length && posn < last)
while (posn < buffer.Length && remaining > 0)
{
var n = ReadTransformOneBlock(buffer, posn, last);
var n = ReadTransformOneBlock(buffer, posn, remaining);
posn += n;
remaining -= n;
}
}

private int ReadTransformOneBlock(Span<byte> buffer, int offset, int last)
private int ReadTransformOneBlock(Span<byte> buffer, int offset, int remaining)
{
if (_isFinalBlock)
if (_counterOutOffset == BLOCK_SIZE_IN_BYTES)
{
throw new ArchiveOperationException();
FillCounterOut();
}

var bytesRemaining = last - offset;
var bytesToRead =
(bytesRemaining > BLOCK_SIZE_IN_BYTES) ? BLOCK_SIZE_IN_BYTES : bytesRemaining;

// update the counter
System.Buffers.Binary.BinaryPrimitives.WriteInt32LittleEndian(_counter, _nonce++);

// Determine if this is the final block
if ((bytesToRead == bytesRemaining) && (_totalBytesLeftToRead == 0))
{
_counterOut = _transform.TransformFinalBlock(_counter, 0, BLOCK_SIZE_IN_BYTES);
_isFinalBlock = true;
}
else
{
_transform.TransformBlock(
_counter,
0, // offset
BLOCK_SIZE_IN_BYTES,
_counterOut,
0
); // offset
}

XorInPlace(buffer, offset, bytesToRead);
return bytesToRead;
var bytesToXor = Math.Min(BLOCK_SIZE_IN_BYTES - _counterOutOffset, remaining);
XorInPlace(buffer, offset, bytesToXor, _counterOutOffset);
_counterOutOffset += bytesToXor;
return bytesToXor;
}

private void XorInPlace(Span<byte> buffer, int offset, int count)
private void XorInPlace(Span<byte> buffer, int offset, int count, int counterOffset)
{
for (var i = 0; i < count; i++)
{
buffer[offset + i] = (byte)(_counterOut[i] ^ buffer[offset + i]);
buffer[offset + i] = (byte)(_counterOut[counterOffset + i] ^ buffer[offset + i]);
}
}
#endif
Expand Down
61 changes: 24 additions & 37 deletions src/SharpCompress/Common/Zip/WinzipAesCryptoStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ internal partial class WinzipAesCryptoStream : Stream
private readonly ICryptoTransform _transform;
private int _nonce = 1;
private byte[] _counterOut = new byte[BLOCK_SIZE_IN_BYTES];
private bool _isFinalBlock;
private int _counterOutOffset = BLOCK_SIZE_IN_BYTES;
private long _totalBytesLeftToRead;
private bool _isDisposed;

Expand Down Expand Up @@ -123,58 +123,45 @@ public override int Read(byte[] buffer, int offset, int count)
return read;
}

private int ReadTransformOneBlock(byte[] buffer, int offset, int last)
private void FillCounterOut()
{
if (_isFinalBlock)
{
throw new ArchiveOperationException();
}

var bytesRemaining = last - offset;
var bytesToRead =
(bytesRemaining > BLOCK_SIZE_IN_BYTES) ? BLOCK_SIZE_IN_BYTES : bytesRemaining;

// update the counter
BinaryPrimitives.WriteInt32LittleEndian(_counter, _nonce++);

// Determine if this is the final block
if ((bytesToRead == bytesRemaining) && (_totalBytesLeftToRead == 0))
{
_counterOut = _transform.TransformFinalBlock(_counter, 0, BLOCK_SIZE_IN_BYTES);
_isFinalBlock = true;
}
else
{
_transform.TransformBlock(
_counter,
0, // offset
BLOCK_SIZE_IN_BYTES,
_counterOut,
0
); // offset
}

XorInPlace(buffer, offset, bytesToRead);
return bytesToRead;
_transform.TransformBlock(
_counter,
0, // offset
BLOCK_SIZE_IN_BYTES,
_counterOut,
0
); // offset
_counterOutOffset = 0;
}

private void XorInPlace(byte[] buffer, int offset, int count)
private void XorInPlace(byte[] buffer, int offset, int count, int counterOffset)
{
for (var i = 0; i < count; i++)
{
buffer[offset + i] = (byte)(_counterOut[i] ^ buffer[offset + i]);
buffer[offset + i] = (byte)(_counterOut[counterOffset + i] ^ buffer[offset + i]);
}
}

private void ReadTransformBlocks(byte[] buffer, int offset, int count)
{
var posn = offset;
var last = count + offset;
var remaining = count;

while (posn < buffer.Length && posn < last)
while (posn < buffer.Length && remaining > 0)
{
var n = ReadTransformOneBlock(buffer, posn, last);
posn += n;
if (_counterOutOffset == BLOCK_SIZE_IN_BYTES)
{
FillCounterOut();
}

var bytesToXor = Math.Min(BLOCK_SIZE_IN_BYTES - _counterOutOffset, remaining);
XorInPlace(buffer, posn, bytesToXor, _counterOutOffset);
_counterOutOffset += bytesToXor;
posn += bytesToXor;
remaining -= bytesToXor;
}
}

Expand Down
6 changes: 2 additions & 4 deletions src/SharpCompress/Common/Zip/ZipFilePart.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,8 @@ protected async ValueTask<Stream> GetCryptoStreamAsync(
}

if (
(
Header.CompressedSize == 0
&& FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor)
) || Header.IsZip64
Header.CompressedSize == 0
&& FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor)
)
{
plainStream = SharpCompressStream.CreateNonDisposing(plainStream); //make sure AES doesn't close
Expand Down
6 changes: 2 additions & 4 deletions src/SharpCompress/Common/Zip/ZipFilePart.cs
Original file line number Diff line number Diff line change
Expand Up @@ -234,10 +234,8 @@ protected Stream GetCryptoStream(Stream plainStream)
}

if (
(
Header.CompressedSize == 0
&& FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor)
) || Header.IsZip64
Header.CompressedSize == 0
&& FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor)
)
{
plainStream = SharpCompressStream.CreateNonDisposing(plainStream); //make sure AES doesn't close
Expand Down
Loading