bring Mono Security to monotouch
[mono.git] / mcs / class / corlib / System.Security.Cryptography / CryptoStream.cs
old mode 100755 (executable)
new mode 100644 (file)
index 2a19140..9190921
@@ -6,21 +6,41 @@
 //     Sebastien Pouliot (sebastien@ximian.com)
 //
 // Portions (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
-// (C) 2004 Novell (http://www.novell.com)
+// Copyright (C) 2004-2005, 2007 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-using System;
 using System.Globalization;
 using System.IO;
 using System.Runtime.InteropServices;
 
 namespace System.Security.Cryptography {
 
+#if NET_2_0
+       [ComVisible (true)]
+#endif
        public class CryptoStream : Stream {
                private Stream _stream;
                private ICryptoTransform _transform;
                private CryptoStreamMode _mode;
-               private byte[] _previousBlock;
                private byte[] _currentBlock;
                private bool _disposed;
                private bool _flushedFinalBlock;
@@ -119,15 +139,19 @@ namespace System.Security.Cryptography {
                        }
                        // yes - buffer.Length will throw a NullReferenceException if buffer is null
                        // but by doing so we match MS implementation
-                       if (offset + count > buffer.Length) {
+                       // re-ordered to avoid integer overflow
+                       if (offset > buffer.Length - count) {
                                throw new ArgumentException ("(offset+count)", 
                                        Locale.GetText ("buffer overflow"));
                        }
-                       // for some strange reason Object_disposedException isn't throw
-                       // instead we get a ArgumentNullException (probably from an internal method)
+                       // for some strange reason ObjectDisposedException isn't throw
                        if (_workingBlock == null) {
-                               throw new ArgumentNullException (
-                                       Locale.GetText ("object _disposed"));
+#if NET_2_0
+                               return 0;
+#else
+                               // instead we get a ArgumentNullException (probably from an internal method)
+                               throw new ArgumentNullException (Locale.GetText ("CryptoStream was disposed."));
+#endif
                        }
 
                        int result = 0;
@@ -151,7 +175,7 @@ namespace System.Security.Cryptography {
                                        int transformed = 0;
 
                                        // load a new block
-                                       _workingCount = _stream.Read (_workingBlock, 0, _workingBlock.Length);
+                                       _workingCount = _stream.Read (_workingBlock, 0, _transform.InputBlockSize);
                                        _endOfStream = (_workingCount < _transform.InputBlockSize);
 
                                        if (!_endOfStream) {
@@ -174,11 +198,14 @@ namespace System.Security.Cryptography {
                                                        length += transformed;
                                                        _transformedCount += transformed;
                                                }
-                                               byte[] input = _transform.TransformFinalBlock (_waitingBlock, 0, _waitingCount);
-                                               transformed = input.Length;
-                                               Array.Copy (input, 0, _transformedBlock, _transformedCount, input.Length);
-                                               // zeroize this last block
-                                               Array.Clear (input, 0, input.Length);
+                                               if (!_flushedFinalBlock) {
+                                                       byte[] input = _transform.TransformFinalBlock (_waitingBlock, 0, _waitingCount);
+                                                       transformed = input.Length;
+                                                       Buffer.BlockCopy (input, 0, _transformedBlock, _transformedCount, input.Length);
+                                                       // zeroize this last block
+                                                       Array.Clear (input, 0, input.Length);
+                                                       _flushedFinalBlock = true;
+                                               }
                                        }
 
                                        length += transformed;
@@ -225,11 +252,17 @@ namespace System.Security.Cryptography {
                                throw new ArgumentOutOfRangeException ("count", 
                                        Locale.GetText ("negative"));
                        }
-                       if (offset + count > buffer.Length) {
+                       // re-ordered to avoid integer overflow
+                       if (offset > buffer.Length - count) {
                                throw new ArgumentException ("(offset+count)", 
                                        Locale.GetText ("buffer overflow"));
                        }
 
+                       if (_stream == null)
+                               throw new ArgumentNullException ("inner stream was diposed");
+
+                       int buffer_length = count;
+
                        // partial block (in progress)
                        if ((_partialCount > 0) && (_partialCount != _transform.InputBlockSize)) {
                                int remainder = _transform.InputBlockSize - _partialCount;
@@ -251,29 +284,27 @@ namespace System.Security.Cryptography {
                                }
 
                                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) / _transform.InputBlockSize);
-                                       if (((_partialCount + count) % _transform.InputBlockSize) == 0) // partial block ?
-                                               numBlock--; // no then reduce
-                                       int multiSize = (numBlock * _transform.InputBlockSize);
-                                       if (numBlock > 0) {
-                                               byte[] multiBlocks = new byte [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);
+                                       // get the biggest multiple of InputBlockSize in count (without mul or div)
+                                       int size = (count & ~(_transform.OutputBlockSize - 1));
+                                       int rem = (count & (_transform.OutputBlockSize - 1));
+                                       // avoid reallocating memory at each call (reuse same buffer whenever possible)
+                                       if (_workingBlock.Length < size) {
+                                               Array.Clear (_workingBlock, 0, _workingBlock.Length);
+                                               _workingBlock = new byte [size];
                                        }
-                                       else {
-                                               Array.Copy (buffer, offset, _workingBlock, _partialCount, count);
-                                               _partialCount += count;
+
+                                       if (size > 0) {
+                                               int len = _transform.TransformBlock (buffer, offset, size, _workingBlock, 0);
+                                               _stream.Write (_workingBlock, 0, len);
                                        }
+
+                                       if (rem > 0)
+                                               Buffer.BlockCopy (buffer, buffer_length - rem, _workingBlock, 0, rem);
+                                       _partialCount = rem;
                                        count = 0; // the last block, if any, is in _workingBlock
-                               }
-                               else {
+                               } else {
                                        int len = Math.Min (_transform.InputBlockSize - _partialCount, count);
-                                       Array.Copy (buffer, bufferPos, _workingBlock, _partialCount, len);
+                                       Buffer.BlockCopy (buffer, bufferPos, _workingBlock, _partialCount, len);
                                        bufferPos += len;
                                        _partialCount += len;
                                        count -= len;
@@ -291,15 +322,17 @@ namespace System.Security.Cryptography {
 
                public void FlushFinalBlock ()
                {
-                       if (_flushedFinalBlock) {
-                               throw new NotSupportedException (
-                                       Locale.GetText ("This method cannot be called twice."));
-                       }
-                       if (_mode != CryptoStreamMode.Write) {
-                               throw new NotSupportedException (
-                                       Locale.GetText ("cannot flush a non-writeable CryptoStream"));
-                       }
-
+                       if (_flushedFinalBlock)
+                               throw new NotSupportedException (Locale.GetText ("This method cannot be called twice."));
+#if NET_2_0
+                       if (_disposed)
+                               throw new NotSupportedException (Locale.GetText ("CryptoStream was disposed."));
+                       if (_mode != CryptoStreamMode.Write)
+                               return;
+#else
+                       if (_mode != CryptoStreamMode.Write)
+                               throw new NotSupportedException (Locale.GetText ("cannot flush a non-writeable CryptoStream"));
+#endif
                        _flushedFinalBlock = true;
                        byte[] finalBuffer = _transform.TransformFinalBlock (_workingBlock, 0, _partialCount);
                        if (_stream != null) {
@@ -325,7 +358,11 @@ namespace System.Security.Cryptography {
                        throw new NotSupportedException ("SetLength");
                }
 
+#if NET_2_0
+               protected override void Dispose (bool disposing) 
+#else
                protected virtual void Dispose (bool disposing) 
+#endif
                {
                        if (!_disposed) {
                                _disposed = true;
@@ -334,13 +371,10 @@ namespace System.Security.Cryptography {
                                        Array.Clear (_workingBlock, 0, _workingBlock.Length);
                                if (_currentBlock != null)
                                        Array.Clear (_currentBlock, 0, _currentBlock.Length);
-                               if (_previousBlock != null)
-                                       Array.Clear (_previousBlock, 0, _previousBlock.Length);
                                if (disposing) {
                                        _stream = null;
                                        _workingBlock = null;
                                        _currentBlock = null;
-                                       _previousBlock = null;
                                }
                        }
                }