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

MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)200
Read(...)900
Write(...)100

File(s)

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

#LineLine coverage
 1using System;
 2using System.IO;
 3using System.Security.Cryptography;
 4
 5namespace 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)
 024      : base(stream, transform, mode)
 25    {
 26
 027      _stream = stream;
 028      _transform = transform;
 029      _slideBuffer = new byte[1024];
 30
 031      _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.
 036       if (mode != CryptoStreamMode.Read) {
 037        throw new Exception("ZipAESStream only for read");
 38      }
 039    }
 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    {
 059      int nBytes = 0;
 060       while (nBytes < count) {
 61        // Calculate buffer quantities vs read-ahead size, and check for sufficient free space
 062        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.
 067        int lengthToRead = _blockAndAuth - byteCount;
 068         if (_slideBuffer.Length - _slideBufFreePos < lengthToRead) {
 69          // Shift the data to the beginning of the buffer
 070          int iTo = 0;
 071           for (int iFrom = _slideBufStartPos; iFrom < _slideBufFreePos; iFrom++, iTo++) {
 072            _slideBuffer[iTo] = _slideBuffer[iFrom];
 73          }
 074          _slideBufFreePos -= _slideBufStartPos;      // Note the -=
 075          _slideBufStartPos = 0;
 76        }
 077        int obtained = _stream.Read(_slideBuffer, _slideBufFreePos, lengthToRead);
 078        _slideBufFreePos += obtained;
 79
 80        // Recalculate how much data we now have
 081        byteCount = _slideBufFreePos - _slideBufStartPos;
 082         if (byteCount >= _blockAndAuth) {
 83          // At least a 16 byte block and an auth code remains.
 084          _transform.TransformBlock(_slideBuffer,
 085                        _slideBufStartPos,
 086                        CRYPTO_BLOCK_SIZE,
 087                        buffer,
 088                        offset);
 089          nBytes += CRYPTO_BLOCK_SIZE;
 090          offset += CRYPTO_BLOCK_SIZE;
 091          _slideBufStartPos += CRYPTO_BLOCK_SIZE;
 092        } else {
 93          // Last round.
 094           if (byteCount > AUTH_CODE_LENGTH) {
 95            // At least one byte of data plus auth code
 096            int finalBlock = byteCount - AUTH_CODE_LENGTH;
 097            _transform.TransformBlock(_slideBuffer,
 098                          _slideBufStartPos,
 099                          finalBlock,
 0100                          buffer,
 0101                          offset);
 102
 0103            nBytes += finalBlock;
 0104            _slideBufStartPos += finalBlock;
 0105           } else if (byteCount < AUTH_CODE_LENGTH)
 0106            throw new Exception("Internal error missed auth code"); // Coding bug
 107                                        // Final block done. Check Auth code.
 0108          byte[] calcAuthCode = _transform.GetAuthCode();
 0109           for (int i = 0; i < AUTH_CODE_LENGTH; i++) {
 0110             if (calcAuthCode[i] != _slideBuffer[_slideBufStartPos + i]) {
 0111              throw new Exception("AES Authentication Code does not match. This is a super-CRC check on the data in the 
 0112                + "The file may be damaged.");
 113            }
 114          }
 115
 0116          break;  // Reached the auth code
 117        }
 118      }
 0119      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.
 0131      throw new NotImplementedException();
 132    }
 133  }
 134}