lalala
[mono.git] / mcs / class / corlib / System.Security.Cryptography / CryptoStream.cs
index 5f57549b1f8784c49df1623bfdf09abc4da8abba..2a19140da866167f13b95c54cffbd570f84ed25f 100755 (executable)
@@ -24,17 +24,16 @@ namespace System.Security.Cryptography {
                private byte[] _currentBlock;
                private bool _disposed;
                private bool _flushedFinalBlock;
-               private int _blockSize;
                private int _partialCount;
                private bool _endOfStream;
-       
+
                private byte[] _waitingBlock;
                private int _waitingCount;
-       
+
                private byte[] _transformedBlock;
                private int _transformedPos;
                private int _transformedCount;
-       
+
                private byte[] _workingBlock;
                private int _workingCount;
                
@@ -53,15 +52,14 @@ namespace System.Security.Cryptography {
                        _mode = mode;
                        _disposed = false;
                        if (transform != null) {
+                               _workingBlock = new byte [transform.InputBlockSize];
                                if (mode == CryptoStreamMode.Read)
-                                       _blockSize = transform.InputBlockSize;
+                                       _currentBlock = new byte [transform.InputBlockSize];
                                else if (mode == CryptoStreamMode.Write)
-                                       _blockSize = transform.OutputBlockSize;
-                               _workingBlock = new byte [_blockSize];
-                               _currentBlock = new byte [_blockSize];
+                                       _currentBlock = new byte [transform.OutputBlockSize];
                        }
                }
-       
+
                ~CryptoStream () 
                {
                        Dispose (false);
@@ -70,11 +68,11 @@ namespace System.Security.Cryptography {
                public override bool CanRead {
                        get { return (_mode == CryptoStreamMode.Read); }
                }
-       
+
                public override bool CanSeek {
                        get { return false; }
                }
-       
+
                public override bool CanWrite {
                        get { return (_mode == CryptoStreamMode.Write); }
                }
@@ -82,29 +80,29 @@ namespace System.Security.Cryptography {
                public override long Length {
                        get { throw new NotSupportedException ("Length"); }
                }
-       
+
                public override long Position {
                        get { throw new NotSupportedException ("Position"); }
                        set { throw new NotSupportedException ("Position"); }
                }
-       
+
                public void Clear () 
                {
                        Dispose (true);
                        GC.SuppressFinalize (this); // not called in Stream.Dispose
                }
-       
+
                // LAMESPEC: A CryptoStream can be close in read mode
                public override void Close () 
                {
                        // only flush in write mode (bugzilla 46143)
                        if ((!_flushedFinalBlock) && (_mode == CryptoStreamMode.Write))
                                FlushFinalBlock ();
-       
+
                        if (_stream != null)
                                _stream.Close ();
                }
-       
+
                public override int Read ([In,Out] byte[] buffer, int offset, int count)
                {
                        if (_mode != CryptoStreamMode.Read) {
@@ -131,35 +129,35 @@ namespace System.Security.Cryptography {
                                throw new ArgumentNullException (
                                        Locale.GetText ("object _disposed"));
                        }
-       
+
                        int result = 0;
                        if ((count == 0) || ((_transformedPos == _transformedCount) && (_endOfStream)))
                                return result;
-       
+
                        if (_waitingBlock == null) {
-                               _transformedBlock = new byte [_blockSize << 2];
+                               _transformedBlock = new byte [_transform.OutputBlockSize << 2];
                                _transformedPos = 0;
                                _transformedCount = 0;
-                               _waitingBlock = new byte [_blockSize];
+                               _waitingBlock = new byte [_transform.InputBlockSize];
                                _waitingCount = _stream.Read (_waitingBlock, 0, _waitingBlock.Length);
                        }
                        
                        while (count > 0) {
                                // transformed but not yet returned
                                int length = (_transformedCount - _transformedPos);
-       
+
                                // need more data - at least one full block must be available if we haven't reach the end of the stream
-                               if (length < _blockSize) {
+                               if (length < _transform.InputBlockSize) {
                                        int transformed = 0;
-       
+
                                        // load a new block
                                        _workingCount = _stream.Read (_workingBlock, 0, _workingBlock.Length);
-                                       _endOfStream = (_workingCount < _blockSize);
-       
+                                       _endOfStream = (_workingCount < _transform.InputBlockSize);
+
                                        if (!_endOfStream) {
                                                // transform the waiting block
                                                transformed = _transform.TransformBlock (_waitingBlock, 0, _waitingBlock.Length, _transformedBlock, _transformedCount);
-       
+
                                                // transfer temporary to waiting
                                                Buffer.BlockCopy (_workingBlock, 0, _waitingBlock, 0, _workingCount);
                                                _waitingCount = _workingCount;
@@ -168,11 +166,11 @@ namespace System.Security.Cryptography {
                                                if (_workingCount > 0) {
                                                        // transform the waiting block
                                                        transformed = _transform.TransformBlock (_waitingBlock, 0, _waitingBlock.Length, _transformedBlock, _transformedCount);
-       
+
                                                        // transfer temporary to waiting
                                                        Buffer.BlockCopy (_workingBlock, 0, _waitingBlock, 0, _workingCount);
                                                        _waitingCount = _workingCount;
-       
+
                                                        length += transformed;
                                                        _transformedCount += transformed;
                                                }
@@ -182,35 +180,37 @@ namespace System.Security.Cryptography {
                                                // zeroize this last block
                                                Array.Clear (input, 0, input.Length);
                                        }
-       
+
                                        length += transformed;
                                        _transformedCount += transformed;
                                }
                                // compaction
-                               if (_transformedPos > _blockSize) {
+                               if (_transformedPos > _transform.InputBlockSize) {
                                        Buffer.BlockCopy (_transformedBlock, _transformedPos, _transformedBlock, 0, length);
                                        _transformedCount -= _transformedPos;
                                        _transformedPos = 0;
                                }
-       
+
                                length = ((count < length) ? count : length);
-                               Buffer.BlockCopy (_transformedBlock, _transformedPos, buffer, offset, length);
-                               _transformedPos += length;
-       
-                               result += length;
-                               offset += length;
-                               count -= length;
-       
+                               if (length > 0) {
+                                       Buffer.BlockCopy (_transformedBlock, _transformedPos, buffer, offset, length);
+                                       _transformedPos += length;
+
+                                       result += length;
+                                       offset += length;
+                                       count -= length;
+                               }
+
                                // there may not be enough data in the stream for a 
                                // complete block
-                               if ((length != _blockSize) || (_endOfStream)) {
+                               if (((length != _transform.InputBlockSize) && (_waitingCount != _transform.InputBlockSize)) || (_endOfStream)) {
                                        count = 0;      // no more data can be read
                                }
                        }
                        
                        return result;
                }
-       
+
                public override void Write (byte[] buffer, int offset, int count)
                {
                        if (_mode != CryptoStreamMode.Write) {
@@ -229,37 +229,38 @@ namespace System.Security.Cryptography {
                                throw new ArgumentException ("(offset+count)", 
                                        Locale.GetText ("buffer overflow"));
                        }
-       
+
                        // partial block (in progress)
-                       if ((_partialCount > 0) && (_partialCount != _blockSize)) {
-                               int remainder = _blockSize - _partialCount;
+                       if ((_partialCount > 0) && (_partialCount != _transform.InputBlockSize)) {
+                               int remainder = _transform.InputBlockSize - _partialCount;
                                remainder = ((count < remainder) ? count : remainder);
                                Buffer.BlockCopy (buffer, offset, _workingBlock, _partialCount, remainder);
                                _partialCount += remainder;
                                offset += remainder;
                                count -= remainder;
                        }
-       
+
                        int bufferPos = offset;
                        while (count > 0) {
-                               if (_partialCount == _blockSize) {
-                                       _partialCount = 0;
+                               if (_partialCount == _transform.InputBlockSize) {
                                        // use partial block to avoid (re)allocation
-                                       _transform.TransformBlock (_workingBlock, 0, _blockSize, _currentBlock, 0);
-                                       _stream.Write (_currentBlock, 0, _currentBlock.Length);
+                                       int len = _transform.TransformBlock (_workingBlock, 0, _partialCount, _currentBlock, 0);
+                                       _stream.Write (_currentBlock, 0, len);
+                                       // reset
+                                       _partialCount = 0;
                                }
-       
+
                                if (_transform.CanTransformMultipleBlocks) {
                                        // transform all except the last block (which may be the last block
                                        // of the stream and require TransformFinalBlock)
-                                       int numBlock = ((_partialCount + count) / _blockSize);
-                                       if (((_partialCount + count) % _blockSize) == 0) // partial block ?
+                                       int numBlock = ((_partialCount + count) / _transform.InputBlockSize);
+                                       if (((_partialCount + count) % _transform.InputBlockSize) == 0) // partial block ?
                                                numBlock--; // no then reduce
-                                       int multiSize = (numBlock * _blockSize);
+                                       int multiSize = (numBlock * _transform.InputBlockSize);
                                        if (numBlock > 0) {
                                                byte[] multiBlocks = new byte [multiSize];
-                                               _transform.TransformBlock (buffer, offset, multiSize, multiBlocks, 0);
-                                               _stream.Write (multiBlocks, 0, multiSize); 
+                                               int len = _transform.TransformBlock (buffer, offset, multiSize, multiBlocks, 0);
+                                               _stream.Write (multiBlocks, 0, len); 
                                                // copy last block into _currentBlock
                                                _partialCount = count - multiSize;
                                                Array.Copy (buffer, offset + multiSize, _workingBlock, 0, _partialCount);
@@ -271,7 +272,7 @@ namespace System.Security.Cryptography {
                                        count = 0; // the last block, if any, is in _workingBlock
                                }
                                else {
-                                       int len = Math.Min (_blockSize - _partialCount, count);
+                                       int len = Math.Min (_transform.InputBlockSize - _partialCount, count);
                                        Array.Copy (buffer, bufferPos, _workingBlock, _partialCount, len);
                                        bufferPos += len;
                                        _partialCount += len;
@@ -281,13 +282,13 @@ namespace System.Security.Cryptography {
                                }
                        }
                }
-       
+
                public override void Flush ()
                {
                        if (_stream != null)
                                _stream.Flush ();
                }
-       
+
                public void FlushFinalBlock ()
                {
                        if (_flushedFinalBlock) {
@@ -298,17 +299,21 @@ namespace System.Security.Cryptography {
                                throw new NotSupportedException (
                                        Locale.GetText ("cannot flush a non-writeable CryptoStream"));
                        }
-       
+
                        _flushedFinalBlock = true;
                        byte[] finalBuffer = _transform.TransformFinalBlock (_workingBlock, 0, _partialCount);
                        if (_stream != null) {
                                _stream.Write (finalBuffer, 0, finalBuffer.Length);
+                               if (_stream is CryptoStream) {
+                                       // for cascading crypto streams
+                                       (_stream as CryptoStream).FlushFinalBlock ();
+                               }
                                _stream.Flush ();
                        }
                        // zeroize
                        Array.Clear (finalBuffer, 0, finalBuffer.Length);
                }
-       
+
                public override long Seek (long offset, SeekOrigin origin)
                {
                        throw new NotSupportedException ("Seek");
@@ -319,7 +324,7 @@ namespace System.Security.Cryptography {
                {
                        throw new NotSupportedException ("SetLength");
                }
-       
+
                protected virtual void Dispose (bool disposing) 
                {
                        if (!_disposed) {