Beispiel #1
0
        /// <summary>
        /// Reads a sequence of bytes from the current stream.
        /// </summary>
        /// <param name="buffer">The buffer that contains decrypted data.</param>
        /// <param name="offset">The offset in buffer at which to begin storing the decrypted data.</param>
        /// <param name="count">The maximum number of bytes to get.</param>
        /// <exception cref="ArgumentOutOfRangeException">Raised when buffer or the internal decryptedBuffer doesn't
        /// contain enough space
        /// </exception>
        /// <exception cref="IOException">Raised when attempting to read from/write to a remote connection which
        /// has been closed</exception>
        /// <returns>The actual number of bytes read into the buffer. Could be less than count</returns>
        public override int Read(byte[] buffer, int offset, int count)
        {
            if (offset > buffer.Length - 1)
            {
                throw new ArgumentOutOfRangeException("offset");
            }

            if (offset + count > buffer.Length)
            {
                throw new ArgumentOutOfRangeException("count");
            }

            if (!IsBufferEmpty())
            {
                if (CheckAvailableCount(count))
                {
                    Array.Copy(decryptedBuffer, this.startIndex, buffer, offset, count);
                    this.startIndex += count;

                    return(count);
                }
                else
                {
                    int sizeRead = this.endIndex - this.startIndex;
                    Array.Copy(decryptedBuffer, this.startIndex, buffer, offset, sizeRead);
                    // All data is read, reset indices
                    this.startIndex = 0;
                    this.endIndex   = 0;

                    return(sizeRead);
                }
            }

            // The buffer is empty, read data from network stream
            byte[] recvBuffer    = new byte[BlockSize];
            byte[] encryptedMsg  = null;
            int    bytesReceived = 0;

            byte[] decryptedMsg      = null;
            bool   triedPooledBuffer = false;

            while (decryptedMsg == null)
            {
                if (!triedPooledBuffer && this.pooledBuffer != null && this.pooledBuffer.Length > 0)
                {// try to decrypte the data in this.pooledBuffer firstly.
                    encryptedMsg = new byte[this.pooledBuffer.Length];
                    Array.Copy(this.pooledBuffer, encryptedMsg, encryptedMsg.Length);
                    this.pooledBuffer = null;
                    triedPooledBuffer = true;
                }
                else
                {
                    // decryptedMsg being null indicates incomplete data, so we continue reading and decrypting.
                    bytesReceived = serverStream.Read(recvBuffer, 0, recvBuffer.Length);

                    // The connection has been closed by remote server
                    if (bytesReceived == 0)
                    {
                        return(0);
                    }

                    // There's pooled data, concatenate the buffer together for decryption
                    if (this.pooledBuffer != null && this.pooledBuffer.Length > 0)
                    {
                        encryptedMsg = new byte[this.pooledBuffer.Length + bytesReceived];
                        Array.Copy(this.pooledBuffer, encryptedMsg, this.pooledBuffer.Length);
                        Array.Copy(recvBuffer, 0, encryptedMsg, this.pooledBuffer.Length, bytesReceived);

                        this.pooledBuffer = null;
                    }
                    else
                    {
                        encryptedMsg = new byte[bytesReceived];
                        Array.Copy(recvBuffer, encryptedMsg, bytesReceived);
                    }
                }

                byte[] extraData = null;
                // Do decryption
                SecurityBuffer[] securityBuffers = new SecurityBuffer[]
                {
                    new SecurityBuffer(SecurityBufferType.Data, encryptedMsg),
                    new SecurityBuffer(SecurityBufferType.Empty, null),
                    new SecurityBuffer(SecurityBufferType.Empty, null),
                    new SecurityBuffer(SecurityBufferType.Empty, null)
                };

                context.Decrypt(securityBuffers);
                for (int i = 0; i < securityBuffers.Length; i++)
                {
                    if (securityBuffers[i].BufferType == SecurityBufferType.Data)
                    {
                        decryptedMsg = ArrayUtility.ConcatenateArrays(decryptedMsg, securityBuffers[i].Buffer);
                    }
                    else if (securityBuffers[i].BufferType == SecurityBufferType.Extra)
                    {
                        extraData = ArrayUtility.ConcatenateArrays(extraData, securityBuffers[i].Buffer);
                    }
                }

                if (extraData != null && extraData.Length > 0)
                {
                    this.pooledBuffer = extraData;
                }
            }

            Array.Copy(decryptedMsg, 0, this.decryptedBuffer, this.endIndex, decryptedMsg.Length);
            this.endIndex += decryptedMsg.Length;

            return(Read(buffer, offset, count));
        }