# ICSharpCode.SharpZipLib.Encryption.ZipAESStream - Coverage Report

# Summary

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

# Metrics

Method | Cyclomatic Complexity | Sequence Coverage | Branch Coverage
--- | --- | --- | ---
.ctor(...) | 2 | 0 | 0
Read(...) | 9 | 0 | 0
Write(...) | 1 | 0 | 0

# File(s)

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

| # | Line |  | Line coverage
--- | --- | --- | --- | ---
|  | `1` |  | `using System;`
|  | `2` |  | `using System.IO;`
|  | `3` |  | `using System.Security.Cryptography;`
|  | `4` |  | ``
|  | `5` |  | `namespace ICSharpCode.SharpZipLib.Encryption`
|  | `6` |  | `{`
|  | `7` |  | `/// <summary>`
|  | `8` |  | `/// Encrypts and decrypts AES ZIP`
|  | `9` |  | `/// </summary>`
|  | `10` |  | `/// <remarks>`
|  | `11` |  | `/// Based on information from http://www.winzip.com/aes_info.htm`
|  | `12` |  | `/// and http://www.gladman.me.uk/cryptography_technology/fileencrypt/`
|  | `13` |  | `/// </remarks>`
|  | `14` |  | `internal class ZipAESStream : CryptoStream`
|  | `15` |  | `{`
|  | `16` |  | ``
|  | `17` |  | `/// <summary>`
|  | `18` |  | `/// Constructor`
|  | `19` |  | `/// </summary>`
|  | `20` |  | `/// <param name="stream">The stream on which to perform the cryptographic transformation.</param>`
|  | `21` |  | `/// <param name="transform">Instance of ZipAESTransform</param>`
|  | `22` |  | `/// <param name="mode">Read or Write</param>`
|  | `23` |  | `public ZipAESStream(Stream stream, ZipAESTransform transform, CryptoStreamMode mode)`
| 0 | `24` |  | `: base(stream, transform, mode)`
|  | `25` |  | `{`
|  | `26` |  | ``
| 0 | `27` |  | `_stream = stream;`
| 0 | `28` |  | `_transform = transform;`
| 0 | `29` |  | `_slideBuffer = new byte[1024];`
|  | `30` |  | ``
| 0 | `31` |  | `_blockAndAuth = CRYPTO_BLOCK_SIZE + AUTH_CODE_LENGTH;`
|  | `32` |  | ``
|  | `33` |  | `// mode:`
|  | `34` |  | `// CryptoStreamMode.Read means we read from "stream" and pass decrypted to our Read() method.`
|  | `35` |  | `// Write bypasses this stream and uses the Transform directly.`
| 0 | `36` |  | `if (mode != CryptoStreamMode.Read) {`
| 0 | `37` |  | `throw new Exception("ZipAESStream only for read");`
|  | `38` |  | `}`
| 0 | `39` |  | `}`
|  | `40` |  | ``
|  | `41` |  | `// The final n bytes of the AES stream contain the Auth Code.`
|  | `42` |  | `private const int AUTH_CODE_LENGTH = 10;`
|  | `43` |  | ``
|  | `44` |  | `private Stream _stream;`
|  | `45` |  | `private ZipAESTransform _transform;`
|  | `46` |  | `private byte[] _slideBuffer;`
|  | `47` |  | `private int _slideBufStartPos;`
|  | `48` |  | `private int _slideBufFreePos;`
|  | `49` |  | `// Blocksize is always 16 here, even for AES-256 which has transform.InputBlockSize of 32.`
|  | `50` |  | `private const int CRYPTO_BLOCK_SIZE = 16;`
|  | `51` |  | `private int _blockAndAuth;`
|  | `52` |  | ``
|  | `53` |  | `/// <summary>`
|  | `54` |  | `/// Reads a sequence of bytes from the current CryptoStream into buffer,`
|  | `55` |  | `/// and advances the position within the stream by the number of bytes read.`
|  | `56` |  | `/// </summary>`
|  | `57` |  | `public override int Read(byte[] buffer, int offset, int count)`
|  | `58` |  | `{`
| 0 | `59` |  | `int nBytes = 0;`
| 0 | `60` |  | `while (nBytes < count) {`
|  | `61` |  | `// Calculate buffer quantities vs read-ahead size, and check for sufficient free space`
| 0 | `62` |  | `int byteCount = _slideBufFreePos - _slideBufStartPos;`
|  | `63` |  | ``
|  | `64` |  | `// Need to handle final block and Auth Code specially, but don't know total data length.`
|  | `65` |  | `// Maintain a read-ahead equal to the length of (crypto block + Auth Code).`
|  | `66` |  | `// When that runs out we can detect these final sections.`
| 0 | `67` |  | `int lengthToRead = _blockAndAuth - byteCount;`
| 0 | `68` |  | `if (_slideBuffer.Length - _slideBufFreePos < lengthToRead) {`
|  | `69` |  | `// Shift the data to the beginning of the buffer`
| 0 | `70` |  | `int iTo = 0;`
| 0 | `71` |  | `for (int iFrom = _slideBufStartPos; iFrom < _slideBufFreePos; iFrom++, iTo++) {`
| 0 | `72` |  | `_slideBuffer[iTo] = _slideBuffer[iFrom];`
|  | `73` |  | `}`
| 0 | `74` |  | `_slideBufFreePos -= _slideBufStartPos; // Note the -=`
| 0 | `75` |  | `_slideBufStartPos = 0;`
|  | `76` |  | `}`
| 0 | `77` |  | `int obtained = _stream.Read(_slideBuffer, _slideBufFreePos, lengthToRead);`
| 0 | `78` |  | `_slideBufFreePos += obtained;`
|  | `79` |  | ``
|  | `80` |  | `// Recalculate how much data we now have`
| 0 | `81` |  | `byteCount = _slideBufFreePos - _slideBufStartPos;`
| 0 | `82` |  | `if (byteCount >= _blockAndAuth) {`
|  | `83` |  | `// At least a 16 byte block and an auth code remains.`
| 0 | `84` |  | `_transform.TransformBlock(_slideBuffer,`
| 0 | `85` |  | `_slideBufStartPos,`
| 0 | `86` |  | `CRYPTO_BLOCK_SIZE,`
| 0 | `87` |  | `buffer,`
| 0 | `88` |  | `offset);`
| 0 | `89` |  | `nBytes += CRYPTO_BLOCK_SIZE;`
| 0 | `90` |  | `offset += CRYPTO_BLOCK_SIZE;`
| 0 | `91` |  | `_slideBufStartPos += CRYPTO_BLOCK_SIZE;`
| 0 | `92` |  | `} else {`
|  | `93` |  | `// Last round.`
| 0 | `94` |  | `if (byteCount > AUTH_CODE_LENGTH) {`
|  | `95` |  | `// At least one byte of data plus auth code`
| 0 | `96` |  | `int finalBlock = byteCount - AUTH_CODE_LENGTH;`
| 0 | `97` |  | `_transform.TransformBlock(_slideBuffer,`
| 0 | `98` |  | `_slideBufStartPos,`
| 0 | `99` |  | `finalBlock,`
| 0 | `100` |  | `buffer,`
| 0 | `101` |  | `offset);`
|  | `102` |  | ``
| 0 | `103` |  | `nBytes += finalBlock;`
| 0 | `104` |  | `_slideBufStartPos += finalBlock;`
| 0 | `105` |  | `} else if (byteCount < AUTH_CODE_LENGTH)`
| 0 | `106` |  | `throw new Exception("Internal error missed auth code"); // Coding bug`
|  | `107` |  | `// Final block done. Check Auth code.`
| 0 | `108` |  | `byte[] calcAuthCode = _transform.GetAuthCode();`
| 0 | `109` |  | `for (int i = 0; i < AUTH_CODE_LENGTH; i++) {`
| 0 | `110` |  | `if (calcAuthCode[i] != _slideBuffer[_slideBufStartPos + i]) {`
| 0 | `111` |  | `throw new Exception("AES Authentication Code does not match. This is a super-CRC check on the data in the`
| 0 | `112` |  | `+ "The file may be damaged.");`
|  | `113` |  | `}`
|  | `114` |  | `}`
|  | `115` |  | ``
| 0 | `116` |  | `break; // Reached the auth code`
|  | `117` |  | `}`
|  | `118` |  | `}`
| 0 | `119` |  | `return nBytes;`
|  | `120` |  | `}`
|  | `121` |  | ``
|  | `122` |  | `/// <summary>`
|  | `123` |  | `/// Writes a sequence of bytes to the current stream and advances the current position within this stream by the num`
|  | `124` |  | `/// </summary>`
|  | `125` |  | `/// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream. </para`
|  | `126` |  | `/// <param name="offset">The byte offset in buffer at which to begin copying bytes to the current stream. </param>`
|  | `127` |  | `/// <param name="count">The number of bytes to be written to the current stream. </param>`
|  | `128` |  | `public override void Write(byte[] buffer, int offset, int count)`
|  | `129` |  | `{`
|  | `130` |  | `// ZipAESStream is used for reading but not for writing. Writing uses the ZipAESTransform directly.`
| 0 | `131` |  | `throw new NotImplementedException();`
|  | `132` |  | `}`
|  | `133` |  | `}`
|  | `134` |  | `}`