SharpZipLib: 256 bit AES Encryption doesn't work

256 bit AES encryption doesn’t work, an error message of “System.ArgumentException: ‘Specified initialization vector (IV) does not match the block size for this algorithm.’” is generated on line 87 of ZipAESTransform.cs during the creation of the encryptor. 128 bit AES encryption works as expected.

_encryptor = rm.CreateEncryptor(byteKey1, byteKey2);

Steps to reproduce

Try and encrypt file with 256bit AES encryption

class Program
{
    static void Main(string[] args)
    {
        ZipFile(@"C:\TEMP\test\test.txt", @"C:\TEMP\test\test.zip", "password");
    }

    public static void ZipFile(string srcPath, string outPath, string password)
    {
        using (ZipOutputStream zipStream = new ZipOutputStream(File.Create(outPath)))
        {
            zipStream.SetLevel(9); // 0-9, 9 being the highest level of compression

            // optional. Null is the same as not setting. Required if using AES.
            zipStream.Password = password; 

            ZipEntry zipEntry = new ZipEntry(Path.GetFileName(srcPath));

            // Specifying the AESKeySize triggers AES encryption. 
            // Allowable values are 0 (off), 128 or 256. 
            // A password on the ZipOutputStream is required if using AES.
            zipEntry.AESKeySize = 256; 
            zipEntry.DateTime = DateTime.Now;

            zipStream.PutNextEntry(zipEntry);

            byte[] buffer = new byte[4096]; // Zip the file in buffered chunks

            using (FileStream fileStream = File.OpenRead(sourceFilePath))
            {
                // Using a fixed size buffer here makes no noticeable difference
                // for output but keeps a lid on memory usage.
                int sourceBytes = fileStream.Read(buffer, 0, buffer.Length);

                while (sourceBytes > 0)
                {
                    zipStream.Write(buffer, 0, sourceBytes);
                    sourceBytes = fileStream.Read(buffer, 0, buffer.Length);
                }
            }
        }
    }
}

Expected behavior

Password protected zip file should be created.

Actual behavior

Fails to encrypt zip file.

Version of SharpZipLib

0.86.0.518

Obtained from (place an x between the brackets for all that apply)

  • Compiled from source
  • branch: master
  • commit: be53259

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 1
  • Comments: 15 (6 by maintainers)

Most upvoted comments

This looks like the solution. Want to make a PR?


From: FastJack2 notifications@github.com Sent: Friday, August 10, 2018 07:25 To: icsharpcode/SharpZipLib Cc: Subscribed Subject: Re: [icsharpcode/SharpZipLib] 256 bit AES Encryption doesn’t work (#181)

The Problem is in ZipAESTransform.cs functino ZipAESTransform()

if you alter it this way, it should work:

`public ZipAESTransform(string key, byte[] saltBytes, int blockSize, bool writeMode) {

	if (blockSize != 16 && blockSize != 32) // 24 valid for AES but not supported by Winzip

		throw new Exception("Invalid blocksize " + blockSize + ". Must be 16 or 32.");

	if (saltBytes.Length != blockSize / 2)

		throw new Exception("Invalid salt len. Must be " + blockSize / 2 + " for blocksize " + blockSize);

	// initialise the encryption buffer and buffer pos

	_blockSize = blockSize;

	_encryptBuffer = new byte[_blockSize];

	_encrPos = ENCRYPT_BLOCK;



	// Performs the equivalent of derive_key in Dr Brian Gladman's pwd2key.c

	var pdb = new Rfc2898DeriveBytes(key, saltBytes, KEY_ROUNDS);

    var rm = new AesManaged();//Aes.Create();

	rm.Mode = CipherMode.ECB;           // No feedback from cipher for CTR mode

	_counterNonce = new byte[_blockSize];

	byte[] byteKey1 = pdb.GetBytes(_blockSize);

	byte[] byteIV = pdb.GetBytes(_blockSize);

    if (byteIV.Length > 16)

    {

        byte[] byteInit = new byte[16];

        Buffer.BlockCopy(byteIV, 0, byteInit, 0, 16);

        byteIV = byteInit;

    }

    _encryptor = rm.CreateEncryptor(byteKey1, byteIV);

	_pwdVerifier = pdb.GetBytes(PWD_VER_LENGTH);

	//

	_hmacsha1 = IncrementalHash.CreateHMAC(HashAlgorithmName.SHA1, byteIV);

	_writeMode = writeMode;

}`

problem seems to be that aes always needs 16 byte IV, even in 256bit mode, so just use the lower 16…

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or mute the thread.

This is planned for v1.1, which will hopefully be released this weekend if I get the time.

The Problem is in ZipAESTransform.cs functino ZipAESTransform()

if you alter it this way, it should work:

public ZipAESTransform(string key, byte[] saltBytes, int blockSize, bool writeMode)
{

    if (blockSize != 16 && blockSize != 32) // 24 valid for AES but not supported by Winzip
        throw new Exception("Invalid blocksize " + blockSize + ". Must be 16 or 32.");
    if (saltBytes.Length != blockSize / 2)
        throw new Exception("Invalid salt len. Must be " + blockSize / 2 + " for blocksize " + blockSize);
    // initialise the encryption buffer and buffer pos
    _blockSize = blockSize;
    _encryptBuffer = new byte[_blockSize];
    _encrPos = ENCRYPT_BLOCK;

    // Performs the equivalent of derive_key in Dr Brian Gladman's pwd2key.c
    var pdb = new Rfc2898DeriveBytes(key, saltBytes, KEY_ROUNDS);
    var rm = new AesManaged();//Aes.Create();
    rm.Mode = CipherMode.ECB;           // No feedback from cipher for CTR mode
    _counterNonce = new byte[_blockSize];
    byte[] byteKey1 = pdb.GetBytes(_blockSize);
    byte[] byteIV = pdb.GetBytes(_blockSize);
    if (byteIV.Length > 16)
    {
        byte[] byteInit = new byte[16];
        Buffer.BlockCopy(byteIV, 0, byteInit, 0, 16);
        byteIV = byteInit;
    }
    _encryptor = rm.CreateEncryptor(byteKey1, byteIV);
    _pwdVerifier = pdb.GetBytes(PWD_VER_LENGTH);
    //
    _hmacsha1 = IncrementalHash.CreateHMAC(HashAlgorithmName.SHA1, byteIV);
    _writeMode = writeMode;
}

problem seems to be that aes always needs 16 byte IV, even in 256bit mode, so just use the lower 16…