// Sebastien Pouliot (sebastien@ximian.com)
//
// Portions (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
-// Copyright (C) 2004-2005 Novell, Inc (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
namespace System.Security.Cryptography {
-#if NET_2_0
[ComVisible (true)]
-#endif
public class CryptoStream : Stream {
private Stream _stream;
private ICryptoTransform _transform;
public CryptoStream (Stream stream, ICryptoTransform transform, CryptoStreamMode mode)
{
- if ((mode == CryptoStreamMode.Read) && (!stream.CanRead)) {
- throw new ArgumentException (
- Locale.GetText ("Can't read on stream"));
- }
- if ((mode == CryptoStreamMode.Write) && (!stream.CanWrite)) {
- throw new ArgumentException (
- Locale.GetText ("Can't write on stream"));
+ if (mode == CryptoStreamMode.Read) {
+ if (!stream.CanRead)
+ throw new ArgumentException (Locale.GetText ("Can't read on stream"));
+ } else if (mode == CryptoStreamMode.Write) {
+ if (!stream.CanWrite)
+ throw new ArgumentException (Locale.GetText ("Can't write on stream"));
+ } else {
+ throw new ArgumentException ("mode");
}
_stream = stream;
_transform = transform;
_mode = mode;
_disposed = false;
if (transform != null) {
- _workingBlock = new byte [transform.InputBlockSize];
- if (mode == CryptoStreamMode.Read)
+ if (mode == CryptoStreamMode.Read) {
_currentBlock = new byte [transform.InputBlockSize];
- else if (mode == CryptoStreamMode.Write)
+ _workingBlock = new byte [transform.InputBlockSize];
+ }
+ else if (mode == CryptoStreamMode.Write) {
_currentBlock = new byte [transform.OutputBlockSize];
+ _workingBlock = new byte [transform.OutputBlockSize];
+ }
}
}
public void Clear ()
{
- Dispose (true);
- GC.SuppressFinalize (this); // not called in Stream.Dispose
+ Close ();
}
// 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 ();
+ base.Close ();
}
public override int Read ([In,Out] byte[] buffer, int offset, int count)
Locale.GetText ("buffer overflow"));
}
// for some strange reason ObjectDisposedException isn't throw
- // instead we get a ArgumentNullException (probably from an internal method)
if (_workingBlock == null) {
- throw new ArgumentNullException (
- Locale.GetText ("object _disposed"));
+ return 0;
}
int result = 0;
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) {
length += transformed;
_transformedCount += transformed;
}
- 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);
+ 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;
_transformedCount += transformed;
}
// compaction
- if (_transformedPos > _transform.InputBlockSize) {
+ if (_transformedPos > _transform.OutputBlockSize) {
Buffer.BlockCopy (_transformedBlock, _transformedPos, _transformedBlock, 0, length);
_transformedCount -= _transformedPos;
_transformedPos = 0;
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;
}
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);
- 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;
- Buffer.BlockCopy (buffer, offset + multiSize, _workingBlock, 0, _partialCount);
+ // get the biggest multiple of InputBlockSize in count (without mul or div)
+ int size = (count & ~(_transform.InputBlockSize - 1));
+ int rem = (count & (_transform.InputBlockSize - 1));
+ // avoid reallocating memory at each call (reuse same buffer whenever possible)
+ int sizeWorkingBlock = (1 + size / _transform.InputBlockSize) * _transform.OutputBlockSize;
+ if (_workingBlock.Length < sizeWorkingBlock) {
+ Array.Clear (_workingBlock, 0, _workingBlock.Length);
+ _workingBlock = new byte [sizeWorkingBlock];
}
- else {
- Buffer.BlockCopy (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);
Buffer.BlockCopy (buffer, bufferPos, _workingBlock, _partialCount, len);
bufferPos += len;
public override void Flush ()
{
- if (_stream != null)
- _stream.Flush ();
}
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 (_disposed)
+ throw new NotSupportedException (Locale.GetText ("CryptoStream was disposed."));
_flushedFinalBlock = true;
byte[] finalBuffer = _transform.TransformFinalBlock (_workingBlock, 0, _partialCount);
- if (_stream != null) {
+ if (_stream != null && _mode == CryptoStreamMode.Write) {
_stream.Write (finalBuffer, 0, finalBuffer.Length);
- if (_stream is CryptoStream) {
- // for cascading crypto streams
- (_stream as CryptoStream).FlushFinalBlock ();
- }
+ }
+ if (_stream is CryptoStream) {
+ // for cascading crypto streams
+ (_stream as CryptoStream).FlushFinalBlock ();
+ } else {
_stream.Flush ();
}
// zeroize
throw new NotSupportedException ("SetLength");
}
-#if NET_2_0
protected override void Dispose (bool disposing)
-#else
- protected virtual void Dispose (bool disposing)
-#endif
{
if (!_disposed) {
+ if (disposing) {
+ if (!_flushedFinalBlock) {
+ FlushFinalBlock ();
+ }
+
+ if (_stream != null)
+ _stream.Close ();
+ }
_disposed = true;
// always cleared for security reason
if (_workingBlock != null)