# ICSharpCode.SharpZipLib.Encryption.ZipAESTransform - Coverage Report

# Summary

Class: | ICSharpCode.SharpZipLib.Encryption.ZipAESTransform
Assembly: | ICSharpCode.SharpZipLib
File(s): | C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Encryption\ZipAESTransform.cs
Covered lines: | 0
Uncovered lines: | 47
Coverable lines: | 47
Total lines: | 183
Line coverage: | 0%
Branch coverage: | 0%

# Metrics

Method | Cyclomatic Complexity | Sequence Coverage | Branch Coverage
--- | --- | --- | ---
.ctor(...) | 4 | 0 | 0
TransformBlock(...) | 6 | 0 | 0
GetAuthCode() | 2 | 0 | 0
TransformFinalBlock(...) | 1 | 0 | 0
Dispose() | 1 | 0 | 0

# File(s)

## C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Encryption\ZipAESTransform.cs

| # | Line |  | Line coverage
--- | --- | --- | --- | ---
|  | `1` |  | `using System;`
|  | `2` |  | `using System.Security.Cryptography;`
|  | `3` |  | ``
|  | `4` |  | `namespace ICSharpCode.SharpZipLib.Encryption`
|  | `5` |  | `{`
|  | `6` |  | `/// <summary>`
|  | `7` |  | `/// Transforms stream using AES in CTR mode`
|  | `8` |  | `/// </summary>`
|  | `9` |  | `internal class ZipAESTransform : ICryptoTransform`
|  | `10` |  | `{`
|  | `11` |  | `private const int PWD_VER_LENGTH = 2;`
|  | `12` |  | ``
|  | `13` |  | `// WinZip use iteration count of 1000 for PBKDF2 key generation`
|  | `14` |  | `private const int KEY_ROUNDS = 1000;`
|  | `15` |  | ``
|  | `16` |  | `// For 128-bit AES (16 bytes) the encryption is implemented as expected.`
|  | `17` |  | `// For 256-bit AES (32 bytes) WinZip do full 256 bit AES of the nonce to create the encryption`
|  | `18` |  | `// block but use only the first 16 bytes of it, and discard the second half.`
|  | `19` |  | `private const int ENCRYPT_BLOCK = 16;`
|  | `20` |  | ``
|  | `21` |  | `private int _blockSize;`
|  | `22` |  | `private readonly ICryptoTransform _encryptor;`
|  | `23` |  | `private readonly byte[] _counterNonce;`
|  | `24` |  | `private byte[] _encryptBuffer;`
|  | `25` |  | `private int _encrPos;`
|  | `26` |  | `private byte[] _pwdVerifier;`
|  | `27` |  | `private HMACSHA1 _hmacsha1;`
|  | `28` |  | `private bool _finalised;`
|  | `29` |  | ``
|  | `30` |  | `private bool _writeMode;`
|  | `31` |  | ``
|  | `32` |  | `/// <summary>`
|  | `33` |  | `/// Constructor.`
|  | `34` |  | `/// </summary>`
|  | `35` |  | `/// <param name="key">Password string</param>`
|  | `36` |  | `/// <param name="saltBytes">Random bytes, length depends on encryption strength.`
|  | `37` |  | `/// 128 bits = 8 bytes, 192 bits = 12 bytes, 256 bits = 16 bytes.</param>`
|  | `38` |  | `/// <param name="blockSize">The encryption strength, in bytes eg 16 for 128 bits.</param>`
|  | `39` |  | `/// <param name="writeMode">True when creating a zip, false when reading. For the AuthCode.</param>`
|  | `40` |  | `///`
| 0 | `41` |  | `public ZipAESTransform(string key, byte[] saltBytes, int blockSize, bool writeMode)`
|  | `42` |  | `{`
|  | `43` |  | ``
| 0 | `44` |  | `if (blockSize != 16 && blockSize != 32) // 24 valid for AES but not supported by Winzip`
| 0 | `45` |  | `throw new Exception("Invalid blocksize " + blockSize + ". Must be 16 or 32.");`
| 0 | `46` |  | `if (saltBytes.Length != blockSize / 2)`
| 0 | `47` |  | `throw new Exception("Invalid salt len. Must be " + blockSize / 2 + " for blocksize " + blockSize);`
|  | `48` |  | `// initialise the encryption buffer and buffer pos`
| 0 | `49` |  | `_blockSize = blockSize;`
| 0 | `50` |  | `_encryptBuffer = new byte[_blockSize];`
| 0 | `51` |  | `_encrPos = ENCRYPT_BLOCK;`
|  | `52` |  | ``
|  | `53` |  | `// Performs the equivalent of derive_key in Dr Brian Gladman's pwd2key.c`
| 0 | `54` |  | `var pdb = new Rfc2898DeriveBytes(key, saltBytes, KEY_ROUNDS);`
| 0 | `55` |  | `var rm = new RijndaelManaged();`
| 0 | `56` |  | `rm.Mode = CipherMode.ECB; // No feedback from cipher for CTR mode`
| 0 | `57` |  | `_counterNonce = new byte[_blockSize];`
| 0 | `58` |  | `byte[] byteKey1 = pdb.GetBytes(_blockSize);`
| 0 | `59` |  | `byte[] byteKey2 = pdb.GetBytes(_blockSize);`
| 0 | `60` |  | `_encryptor = rm.CreateEncryptor(byteKey1, byteKey2);`
| 0 | `61` |  | `_pwdVerifier = pdb.GetBytes(PWD_VER_LENGTH);`
|  | `62` |  | `//`
| 0 | `63` |  | `_hmacsha1 = new HMACSHA1(byteKey2);`
| 0 | `64` |  | `_writeMode = writeMode;`
| 0 | `65` |  | `}`
|  | `66` |  | ``
|  | `67` |  | `/// <summary>`
|  | `68` |  | `/// Implement the ICryptoTransform method.`
|  | `69` |  | `/// </summary>`
|  | `70` |  | `public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset`
|  | `71` |  | `{`
|  | `72` |  | ``
|  | `73` |  | `// Pass the data stream to the hash algorithm for generating the Auth Code.`
|  | `74` |  | `// This does not change the inputBuffer. Do this before decryption for read mode.`
| 0 | `75` |  | `if (!_writeMode) {`
| 0 | `76` |  | `_hmacsha1.TransformBlock(inputBuffer, inputOffset, inputCount, inputBuffer, inputOffset);`
|  | `77` |  | `}`
|  | `78` |  | `// Encrypt with AES in CTR mode. Regards to Dr Brian Gladman for this.`
| 0 | `79` |  | `int ix = 0;`
| 0 | `80` |  | `while (ix < inputCount) {`
| 0 | `81` |  | `if (_encrPos == ENCRYPT_BLOCK) {`
|  | `82` |  | `/* increment encryption nonce */`
| 0 | `83` |  | `int j = 0;`
| 0 | `84` |  | `while (++_counterNonce[j] == 0) {`
| 0 | `85` |  | `++j;`
|  | `86` |  | `}`
|  | `87` |  | `/* encrypt the nonce to form next xor buffer */`
| 0 | `88` |  | `_encryptor.TransformBlock(_counterNonce, 0, _blockSize, _encryptBuffer, 0);`
| 0 | `89` |  | `_encrPos = 0;`
|  | `90` |  | `}`
| 0 | `91` |  | `outputBuffer[ix + outputOffset] = (byte)(inputBuffer[ix + inputOffset] ^ _encryptBuffer[_encrPos++]);`
|  | `92` |  | `//`
| 0 | `93` |  | `ix++;`
|  | `94` |  | `}`
| 0 | `95` |  | `if (_writeMode) {`
|  | `96` |  | `// This does not change the buffer.`
| 0 | `97` |  | `_hmacsha1.TransformBlock(outputBuffer, outputOffset, inputCount, outputBuffer, outputOffset);`
|  | `98` |  | `}`
| 0 | `99` |  | `return inputCount;`
|  | `100` |  | `}`
|  | `101` |  | ``
|  | `102` |  | `/// <summary>`
|  | `103` |  | `/// Returns the 2 byte password verifier`
|  | `104` |  | `/// </summary>`
|  | `105` |  | `public byte[] PwdVerifier {`
|  | `106` |  | `get {`
| 0 | `107` |  | `return _pwdVerifier;`
|  | `108` |  | `}`
|  | `109` |  | `}`
|  | `110` |  | ``
|  | `111` |  | `/// <summary>`
|  | `112` |  | `/// Returns the 10 byte AUTH CODE to be checked or appended immediately following the AES data stream.`
|  | `113` |  | `/// </summary>`
|  | `114` |  | `public byte[] GetAuthCode()`
|  | `115` |  | `{`
|  | `116` |  | `// We usually don't get advance notice of final block. Hash requres a TransformFinal.`
| 0 | `117` |  | `if (!_finalised) {`
| 0 | `118` |  | `byte[] dummy = new byte[0];`
| 0 | `119` |  | `_hmacsha1.TransformFinalBlock(dummy, 0, 0);`
| 0 | `120` |  | `_finalised = true;`
|  | `121` |  | `}`
| 0 | `122` |  | `return _hmacsha1.Hash;`
|  | `123` |  | `}`
|  | `124` |  | ``
|  | `125` |  | `#region ICryptoTransform Members`
|  | `126` |  | ``
|  | `127` |  | `/// <summary>`
|  | `128` |  | `/// Not implemented.`
|  | `129` |  | `/// </summary>`
|  | `130` |  | `public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)`
|  | `131` |  | `{`
|  | `132` |  | ``
| 0 | `133` |  | `throw new NotImplementedException("ZipAESTransform.TransformFinalBlock");`
|  | `134` |  | `}`
|  | `135` |  | ``
|  | `136` |  | `/// <summary>`
|  | `137` |  | `/// Gets the size of the input data blocks in bytes.`
|  | `138` |  | `/// </summary>`
|  | `139` |  | `public int InputBlockSize {`
|  | `140` |  | `get {`
| 0 | `141` |  | `return _blockSize;`
|  | `142` |  | `}`
|  | `143` |  | `}`
|  | `144` |  | ``
|  | `145` |  | `/// <summary>`
|  | `146` |  | `/// Gets the size of the output data blocks in bytes.`
|  | `147` |  | `/// </summary>`
|  | `148` |  | `public int OutputBlockSize {`
|  | `149` |  | `get {`
| 0 | `150` |  | `return _blockSize;`
|  | `151` |  | `}`
|  | `152` |  | `}`
|  | `153` |  | ``
|  | `154` |  | `/// <summary>`
|  | `155` |  | `/// Gets a value indicating whether multiple blocks can be transformed.`
|  | `156` |  | `/// </summary>`
|  | `157` |  | `public bool CanTransformMultipleBlocks {`
|  | `158` |  | `get {`
| 0 | `159` |  | `return true;`
|  | `160` |  | `}`
|  | `161` |  | `}`
|  | `162` |  | ``
|  | `163` |  | `/// <summary>`
|  | `164` |  | `/// Gets a value indicating whether the current transform can be reused.`
|  | `165` |  | `/// </summary>`
|  | `166` |  | `public bool CanReuseTransform {`
|  | `167` |  | `get {`
| 0 | `168` |  | `return true;`
|  | `169` |  | `}`
|  | `170` |  | `}`
|  | `171` |  | ``
|  | `172` |  | `/// <summary>`
|  | `173` |  | `/// Cleanup internal state.`
|  | `174` |  | `/// </summary>`
|  | `175` |  | `public void Dispose()`
|  | `176` |  | `{`
| 0 | `177` |  | `_encryptor.Dispose();`
| 0 | `178` |  | `}`
|  | `179` |  | ``
|  | `180` |  | `#endregion`
|  | `181` |  | ``
|  | `182` |  | `}`
|  | `183` |  | `}`