Skip to content

Commit

Permalink
Merge branch 'icsharpcode:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
modio-jackson committed May 26, 2021
2 parents c230218 + 8c0a169 commit d1bfdba
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 88 deletions.
70 changes: 51 additions & 19 deletions .github/workflows/build-test.yml
Expand Up @@ -22,7 +22,9 @@ jobs:
LIB_PROJ: src/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib.csproj
steps:
- uses: actions/checkout@v2

with:
fetch-depth: 0

- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
Expand All @@ -39,46 +41,76 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu, windows, macos]
# Windows testing is combined with code coverage
os: [ubuntu, macos]
target: [netcoreapp3.1]
include:
- os: windows
target: net46
steps:
- uses: actions/checkout@v2

with:
fetch-depth: 0

- name: Setup .NET Core
if: matrix.target == 'netcoreapp3.1'
uses: actions/setup-dotnet@v1
with:
dotnet-version: '3.1.x'

# NOTE: This is the temporary fix for https://github.com/actions/virtual-environments/issues/1090
- name: Cleanup before restore
if: ${{ matrix.os == 'windows' }}
run: dotnet clean ICSharpCode.SharpZipLib.sln && dotnet nuget locals all --clear

- name: Restore test dependencies
run: dotnet restore

- name: Run tests (Debug)
run: dotnet test -c debug -f ${{ matrix.target }} --no-restore

- name: Run tests (Release)
# Only upload code coverage for windows in an attempt to fix the broken code coverage
if: ${{ matrix.os == 'windows' }}
run: dotnet test -c release -f ${{ matrix.target }} --no-restore --collect="XPlat Code Coverage"

- name: Run tests with coverage (Release)
# Only upload code coverage for windows in an attempt to fix the broken code coverage
if: ${{ matrix.os != 'windows' }}
run: dotnet test -c release -f ${{ matrix.target }} --no-restore


CodeCov:
name: Code Coverage
runs-on: windows-latest
env:
DOTCOVER_VER: 2021.1.2
DOTCOVER_PKG: jetbrains.dotcover.commandlinetools
COVER_SNAPSHOT: SharpZipLib.dcvr
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0

- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: '3.1.x'

# NOTE: This is the temporary fix for https://github.com/actions/virtual-environments/issues/1090
- name: Cleanup before restore
run: dotnet clean ICSharpCode.SharpZipLib.sln && dotnet nuget locals all --clear

- name: Install codecov
run: nuget install -o tools -version ${{env.DOTCOVER_VER}} ${{env.DOTCOVER_PKG}}

- name: Add dotcover to path
run: echo "$(pwd)\tools\${{env.DOTCOVER_PKG}}.${{env.DOTCOVER_VER}}\tools" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append

- name: Run tests with code coverage
run: dotcover dotnet --output=${{env.COVER_SNAPSHOT}} --filters=-:ICSharpCode.SharpZipLib.Tests -- test -c release

- name: Create code coverage report
run: dotcover report --source=${{env.COVER_SNAPSHOT}} --reporttype=detailedxml --output=dotcover-report.xml

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1.2.2
with:
files: dotcover-report.xml

- name: Upload coverage snapshot artifact
uses: actions/upload-artifact@v2
with:
name: Code coverage snapshot
path: ${{env.COVER_SNAPSHOT}}

Pack:
needs: [Build, Test]
needs: [Build, Test, CodeCov]
runs-on: windows-latest
env:
PKG_SUFFIX: ''
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -253,3 +253,4 @@ paket-files/
/test/ICSharpCode.SharpZipLib.TestBootstrapper/Properties/launchSettings.json
_testRunner/
docs/help/api/.manifest
/benchmark/ICSharpCode.SharpZipLib.Benchmark/BenchmarkDotNet.Artifacts/results
21 changes: 21 additions & 0 deletions benchmark/ICSharpCode.SharpZipLib.Benchmark/Zip/ZipOutputStream.cs
@@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;

namespace ICSharpCode.SharpZipLib.Benchmark.Zip
Expand Down Expand Up @@ -37,5 +38,25 @@ public long WriteZipOutputStream()
return memoryStream.Position;
}
}

[Benchmark]
public async Task<long> WriteZipOutputStreamAsync()
{
using (var memoryStream = new MemoryStream(outputBuffer))
{
using (var zipOutputStream = new SharpZipLib.Zip.ZipOutputStream(memoryStream))
{
zipOutputStream.IsStreamOwner = false;
zipOutputStream.PutNextEntry(new SharpZipLib.Zip.ZipEntry("0"));

for (int i = 0; i < ChunkCount; i++)
{
await zipOutputStream.WriteAsync(inputBuffer, 0, inputBuffer.Length);
}
}

return memoryStream.Position;
}
}
}
}
Expand Up @@ -153,37 +153,15 @@ public bool CanPatchEntries

#region Encryption

private string password;

private ICryptoTransform cryptoTransform_;

/// <summary>
/// Returns the 10 byte AUTH CODE to be appended immediately following the AES data stream.
/// The CryptoTransform currently being used to encrypt the compressed data.
/// </summary>
protected byte[] AESAuthCode;
protected ICryptoTransform cryptoTransform_;

/// <summary>
/// Get/set the password used for encryption.
/// Returns the 10 byte AUTH CODE to be appended immediately following the AES data stream.
/// </summary>
/// <remarks>When set to null or if the password is empty no encryption is performed</remarks>
public string Password
{
get
{
return password;
}
set
{
if ((value != null) && (value.Length == 0))
{
password = null;
}
else
{
password = value;
}
}
}
protected byte[] AESAuthCode;

/// <summary>
/// Encrypt a block of data
Expand All @@ -202,34 +180,6 @@ protected void EncryptBlock(byte[] buffer, int offset, int length)
cryptoTransform_.TransformBlock(buffer, 0, length, buffer, 0);
}

/// <summary>
/// Initializes encryption keys based on given <paramref name="password"/>.
/// </summary>
/// <param name="password">The password.</param>
protected void InitializePassword(string password)
{
var pkManaged = new PkzipClassicManaged();
byte[] key = PkzipClassic.GenerateKeys(ZipStrings.ConvertToArray(password));
cryptoTransform_ = pkManaged.CreateEncryptor(key, null);
}

/// <summary>
/// Initializes encryption keys based on given password.
/// </summary>
protected void InitializeAESPassword(ZipEntry entry, string rawPassword,
out byte[] salt, out byte[] pwdVerifier)
{
salt = new byte[entry.AESSaltLen];
// Salt needs to be cryptographically random, and unique per file
if (_aesRnd == null)
_aesRnd = RandomNumberGenerator.Create();
_aesRnd.GetBytes(salt);
int blockSize = entry.AESKeySize / 8; // bits to bytes

cryptoTransform_ = new ZipAESTransform(rawPassword, salt, blockSize, true);
pwdVerifier = ((ZipAESTransform)cryptoTransform_).PwdVerifier;
}

#endregion Encryption

#region Deflation Support
Expand Down Expand Up @@ -484,12 +434,5 @@ public override void Write(byte[] buffer, int offset, int count)
private bool isClosed_;

#endregion Instance Fields

#region Static Fields

// Static to help ensure that multiple files within a zip will get different random salt
private static RandomNumberGenerator _aesRnd = RandomNumberGenerator.Create();

#endregion Static Fields
}
}
64 changes: 64 additions & 0 deletions src/ICSharpCode.SharpZipLib/Zip/ZipOutputStream.cs
@@ -1,5 +1,6 @@
using ICSharpCode.SharpZipLib.Checksum;
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Encryption;
using ICSharpCode.SharpZipLib.Zip.Compression;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
using System;
Expand Down Expand Up @@ -154,6 +155,29 @@ public UseZip64 UseZip64
/// </summary>
public INameTransform NameTransform { get; set; } = new PathTransformer();

/// <summary>
/// Get/set the password used for encryption.
/// </summary>
/// <remarks>When set to null or if the password is empty no encryption is performed</remarks>
public string Password
{
get
{
return password;
}
set
{
if ((value != null) && (value.Length == 0))
{
password = null;
}
else
{
password = value;
}
}
}

/// <summary>
/// Write an unsigned short in little endian byte order.
/// </summary>
Expand Down Expand Up @@ -634,6 +658,34 @@ public void CloseEntry()
curEntry = null;
}

/// <summary>
/// Initializes encryption keys based on given <paramref name="password"/>.
/// </summary>
/// <param name="password">The password.</param>
private void InitializePassword(string password)
{
var pkManaged = new PkzipClassicManaged();
byte[] key = PkzipClassic.GenerateKeys(ZipStrings.ConvertToArray(password));
cryptoTransform_ = pkManaged.CreateEncryptor(key, null);
}

/// <summary>
/// Initializes encryption keys based on given password.
/// </summary>
private void InitializeAESPassword(ZipEntry entry, string rawPassword,
out byte[] salt, out byte[] pwdVerifier)
{
salt = new byte[entry.AESSaltLen];

// Salt needs to be cryptographically random, and unique per file
_aesRnd.GetBytes(salt);

int blockSize = entry.AESKeySize / 8; // bits to bytes

cryptoTransform_ = new ZipAESTransform(rawPassword, salt, blockSize, true);
pwdVerifier = ((ZipAESTransform)cryptoTransform_).PwdVerifier;
}

private void WriteEncryptionHeader(long crcValue)
{
offset += ZipConstants.CryptoHeaderSize;
Expand Down Expand Up @@ -1010,6 +1062,18 @@ public override void Flush()
// NOTE: Setting the size for entries before they are added is the best solution!
private UseZip64 useZip64_ = UseZip64.Dynamic;

/// <summary>
/// The password to use when encrypting archive entries.
/// </summary>
private string password;

#endregion Instance Fields

#region Static Fields

// Static to help ensure that multiple files within a zip will get different random salt
private static RandomNumberGenerator _aesRnd = RandomNumberGenerator.Create();

#endregion Static Fields
}
}
5 changes: 4 additions & 1 deletion test/ICSharpCode.SharpZipLib.Tests/BZip2/Bzip2Tests.cs
Expand Up @@ -12,6 +12,9 @@ namespace ICSharpCode.SharpZipLib.Tests.BZip2
[TestFixture]
public class BZip2Suite
{
// Use the same random seed to guarantee all the code paths are followed
const int RandomSeed = 4;

/// <summary>
/// Basic compress/decompress test BZip2
/// </summary>
Expand All @@ -23,7 +26,7 @@ public void BasicRoundTrip()
var outStream = new BZip2OutputStream(ms);

byte[] buf = new byte[10000];
var rnd = new Random();
var rnd = new Random(RandomSeed);
rnd.NextBytes(buf);

outStream.Write(buf, 0, buf.Length);
Expand Down
Expand Up @@ -16,6 +16,9 @@ namespace ICSharpCode.SharpZipLib.Tests.Base
[TestFixture]
public class InflaterDeflaterTestSuite
{
// Use the same random seed to guarantee all the code paths are followed
const int RandomSeed = 5;

private void Inflate(MemoryStream ms, byte[] original, int level, bool zlib)
{
byte[] buf2 = new byte[original.Length];
Expand Down Expand Up @@ -60,7 +63,7 @@ private MemoryStream Deflate(byte[] data, int level, bool zlib)
private static byte[] GetRandomTestData(int size)
{
byte[] buffer = new byte[size];
var rnd = new Random();
var rnd = new Random(RandomSeed);
rnd.NextBytes(buffer);

return buffer;
Expand Down Expand Up @@ -184,7 +187,7 @@ public async Task InflateDeflateZlibAsync([Range(0, 9)] int level)
private int runLevel;
private bool runZlib;
private long runCount;
private readonly Random runRandom = new Random(5);
private readonly Random runRandom = new Random(RandomSeed);

private void DeflateAndInflate(byte[] buffer)
{
Expand Down
Expand Up @@ -8,15 +8,10 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="3.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
<PackageReference Include="nunit" Version="3.13.1" />
<PackageReference Include="nunit.console" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
<PackageReference Include="OpenCover" Version="4.6.519" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.4.0" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
</ItemGroup>
Expand Down

0 comments on commit d1bfdba

Please sign in to comment.