Skip to content

Commit

Permalink
PR #604: Move the Password property from DeflaterOutputStream into Zi…
Browse files Browse the repository at this point in the history
…pOutputStream

* Move the Password property from DeflaterOutputStream into ZipOutputStream
* Move cryptoTransform setup machinery from DeflatorOutputStream to ZipOutputStream
* remove duplicate setup of _aesRnd
  • Loading branch information
Numpsy committed May 13, 2021
1 parent 232d690 commit 08c40e8
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 61 deletions.
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
}
}

0 comments on commit 08c40e8

Please sign in to comment.