Code:
/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / clr / src / BCL / System / Security / Cryptography / CryptoStream.cs / 1 / CryptoStream.cs
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
//
// CryptoStream.cs
//
namespace System.Security.Cryptography {
using System;
using System.IO;
using System.Runtime.InteropServices;
[Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public enum CryptoStreamMode {
Read = 0,
Write = 1,
}
[System.Runtime.InteropServices.ComVisible(true)]
public class CryptoStream : Stream, IDisposable {
// Member veriables
private Stream _stream;
private ICryptoTransform _Transform;
private byte[] _InputBuffer; // read from _stream before _Transform
private int _InputBufferIndex = 0;
private int _InputBlockSize;
private byte[] _OutputBuffer; // buffered output of _Transform
private int _OutputBufferIndex = 0;
private int _OutputBlockSize;
private CryptoStreamMode _transformMode;
private bool _canRead = false;
private bool _canWrite = false;
private bool _finalBlockTransformed = false;
// Constructors
public CryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode) {
_stream = stream;
_transformMode = mode;
_Transform = transform;
switch (_transformMode) {
case CryptoStreamMode.Read:
if (!(_stream.CanRead)) throw new ArgumentException(Environment.GetResourceString("Argument_StreamNotReadable"),"stream");
_canRead = true;
break;
case CryptoStreamMode.Write:
if (!(_stream.CanWrite)) throw new ArgumentException(Environment.GetResourceString("Argument_StreamNotWritable"),"stream");
_canWrite = true;
break;
default:
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidValue"));
}
InitializeBuffer();
}
public override bool CanRead {
get { return _canRead; }
}
// For now, assume we can never seek into the middle of a cryptostream
// and get the state right. This is too strict.
public override bool CanSeek {
get { return false; }
}
public override bool CanWrite {
get { return _canWrite; }
}
public override long Length {
get { throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnseekableStream")); }
}
public override long Position {
get { throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnseekableStream")); }
set { throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnseekableStream")); }
}
// The flush final block functionality used to be part of close, but that meant you couldn't do something like this:
// MemoryStream ms = new MemoryStream();
// CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
// cs.Write(foo, 0, foo.Length);
// cs.Close();
// and get the encrypted data out of ms, because the cs.Close also closed ms and the data went away.
// so now do this:
// cs.Write(foo, 0, foo.Length);
// cs.FlushFinalBlock() // which can only be called once
// byte[] ciphertext = ms.ToArray();
// cs.Close();
public void FlushFinalBlock() {
if (_finalBlockTransformed)
throw new NotSupportedException(Environment.GetResourceString("Cryptography_CryptoStream_FlushFinalBlockTwice"));
// We have to process the last block here. First, we have the final block in _InputBuffer, so transform it
byte[] finalBytes = _Transform.TransformFinalBlock(_InputBuffer, 0, _InputBufferIndex);
_finalBlockTransformed = true;
// Now, write out anything sitting in the _OutputBuffer...
if (_canWrite && _OutputBufferIndex > 0) {
_stream.Write(_OutputBuffer, 0, _OutputBufferIndex);
_OutputBufferIndex = 0;
}
// Write out finalBytes
if (_canWrite)
_stream.Write(finalBytes, 0, finalBytes.Length);
// If the inner stream is a CryptoStream, then we want to call FlushFinalBlock on it too, otherwise just Flush.
if (_stream is CryptoStream) {
((CryptoStream) _stream).FlushFinalBlock();
} else {
_stream.Flush();
}
// zeroize plain text material before returning
if (_InputBuffer != null)
Array.Clear(_InputBuffer, 0, _InputBuffer.Length);
if (_OutputBuffer != null)
Array.Clear(_OutputBuffer, 0, _OutputBuffer.Length);
return;
}
public override void Flush() {
return;
}
public override long Seek(long offset, SeekOrigin origin) {
throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnseekableStream"));
}
public override void SetLength(long value) {
throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnseekableStream"));
}
public override int Read([In, Out] byte[] buffer, int offset, int count) {
// argument checking
if (!_canRead)
throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnreadableStream"));
if (offset < 0)
throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (count < 0)
throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (buffer.Length - offset < count)
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
// read <= count bytes from the input stream, transforming as we go.
// Basic idea: first we deliver any bytes we already have in the
// _OutputBuffer, because we know they're good. Then, if asked to deliver
// more bytes, we read & transform a block at a time until either there are
// no bytes ready or we've delivered enough.
int bytesToDeliver = count;
int currentOutputIndex = offset;
if (_OutputBufferIndex != 0) {
// we have some already-transformed bytes in the output buffer
if (_OutputBufferIndex <= count) {
Buffer.InternalBlockCopy(_OutputBuffer, 0, buffer, offset, _OutputBufferIndex);
bytesToDeliver -= _OutputBufferIndex;
currentOutputIndex += _OutputBufferIndex;
_OutputBufferIndex = 0;
} else {
Buffer.InternalBlockCopy(_OutputBuffer, 0, buffer, offset, count);
Buffer.InternalBlockCopy(_OutputBuffer, count, _OutputBuffer, 0, _OutputBufferIndex - count);
_OutputBufferIndex -= count;
return(count);
}
}
// _finalBlockTransformed == true implies we're at the end of the input stream
// if we got through the previous if block then _OutputBufferIndex = 0, meaning
// we have no more transformed bytes to give
// so return count-bytesToDeliver, the amount we were able to hand back
// eventually, we'll just always return 0 here because there's no more to read
if (_finalBlockTransformed) {
return(count - bytesToDeliver);
}
// ok, now loop until we've delivered enough or there's nothing available
int amountRead = 0;
int numOutputBytes;
// OK, see first if it's a multi-block transform and we can speed up things
if (bytesToDeliver > _OutputBlockSize)
{
if (_Transform.CanTransformMultipleBlocks) {
int BlocksToProcess = bytesToDeliver / _OutputBlockSize;
int numWholeBlocksInBytes = BlocksToProcess * _InputBlockSize;
byte[] tempInputBuffer = new byte[numWholeBlocksInBytes];
// get first the block already read
Buffer.InternalBlockCopy(_InputBuffer, 0, tempInputBuffer, 0, _InputBufferIndex);
amountRead = _InputBufferIndex;
amountRead += _stream.Read(tempInputBuffer, _InputBufferIndex, numWholeBlocksInBytes - _InputBufferIndex);
_InputBufferIndex = 0;
if (amountRead <= _InputBlockSize) {
_InputBuffer = tempInputBuffer;
_InputBufferIndex = amountRead;
goto slow;
}
// Make amountRead an integral multiple of _InputBlockSize
int numWholeReadBlocksInBytes = (amountRead / _InputBlockSize) * _InputBlockSize;
int numIgnoredBytes = amountRead - numWholeReadBlocksInBytes;
if (numIgnoredBytes != 0) {
_InputBufferIndex = numIgnoredBytes;
Buffer.InternalBlockCopy(tempInputBuffer, numWholeReadBlocksInBytes, _InputBuffer, 0, numIgnoredBytes);
}
byte[] tempOutputBuffer = new byte[(numWholeReadBlocksInBytes / _InputBlockSize) * _OutputBlockSize];
numOutputBytes = _Transform.TransformBlock(tempInputBuffer, 0, numWholeReadBlocksInBytes, tempOutputBuffer, 0);
Buffer.InternalBlockCopy(tempOutputBuffer, 0, buffer, currentOutputIndex, numOutputBytes);
// Now, tempInputBuffer and tempOutputBuffer are no more needed, so zeroize them to protect plain text
Array.Clear(tempInputBuffer, 0, tempInputBuffer.Length);
Array.Clear(tempOutputBuffer, 0, tempOutputBuffer.Length);
bytesToDeliver -= numOutputBytes;
currentOutputIndex += numOutputBytes;
}
}
slow:
// try to fill _InputBuffer so we have something to transform
while (bytesToDeliver > 0) {
while (_InputBufferIndex < _InputBlockSize) {
amountRead = _stream.Read(_InputBuffer, _InputBufferIndex, _InputBlockSize - _InputBufferIndex);
// first, check to see if we're at the end of the input stream
if (amountRead == 0) goto ProcessFinalBlock;
_InputBufferIndex += amountRead;
}
numOutputBytes = _Transform.TransformBlock(_InputBuffer, 0, _InputBlockSize, _OutputBuffer, 0);
_InputBufferIndex = 0;
if (bytesToDeliver >= numOutputBytes) {
Buffer.InternalBlockCopy(_OutputBuffer, 0, buffer, currentOutputIndex, numOutputBytes);
currentOutputIndex += numOutputBytes;
bytesToDeliver -= numOutputBytes;
} else {
Buffer.InternalBlockCopy(_OutputBuffer, 0, buffer, currentOutputIndex, bytesToDeliver);
_OutputBufferIndex = numOutputBytes - bytesToDeliver;
Buffer.InternalBlockCopy(_OutputBuffer, bytesToDeliver, _OutputBuffer, 0, _OutputBufferIndex);
return count;
}
}
return count;
ProcessFinalBlock:
// if so, then call TransformFinalBlock to get whatever is left
byte[] finalBytes = _Transform.TransformFinalBlock(_InputBuffer, 0, _InputBufferIndex);
// now, since _OutputBufferIndex must be 0 if we're in the while loop at this point,
// reset it to be what we just got back
_OutputBuffer = finalBytes;
_OutputBufferIndex = finalBytes.Length;
// set the fact that we've transformed the final block
_finalBlockTransformed = true;
// now, return either everything we just got or just what's asked for, whichever is smaller
if (bytesToDeliver < _OutputBufferIndex) {
Buffer.InternalBlockCopy(_OutputBuffer, 0, buffer, currentOutputIndex, bytesToDeliver);
_OutputBufferIndex -= bytesToDeliver;
Buffer.InternalBlockCopy(_OutputBuffer, bytesToDeliver, _OutputBuffer, 0, _OutputBufferIndex);
return(count);
} else {
Buffer.InternalBlockCopy(_OutputBuffer, 0, buffer, currentOutputIndex, _OutputBufferIndex);
bytesToDeliver -= _OutputBufferIndex;
_OutputBufferIndex = 0;
return(count - bytesToDeliver);
}
}
public override void Write(byte[] buffer, int offset, int count) {
if (!_canWrite)
throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnwritableStream"));
if (offset < 0)
throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (count < 0)
throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (buffer.Length - offset < count)
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
// write <= count bytes to the output stream, transforming as we go.
// Basic idea: using bytes in the _InputBuffer first, make whole blocks,
// transform them, and write them out. Cache any remaining bytes in the _InputBuffer.
int bytesToWrite = count;
int currentInputIndex = offset;
// if we have some bytes in the _InputBuffer, we have to deal with those first,
// so let's try to make an entire block out of it
if (_InputBufferIndex > 0) {
if (count >= _InputBlockSize - _InputBufferIndex) {
// we have enough to transform at least a block, so fill the input block
Buffer.InternalBlockCopy(buffer, offset, _InputBuffer, _InputBufferIndex, _InputBlockSize - _InputBufferIndex);
currentInputIndex += (_InputBlockSize - _InputBufferIndex);
bytesToWrite -= (_InputBlockSize - _InputBufferIndex);
_InputBufferIndex = _InputBlockSize;
// Transform the block and write it out
} else {
// not enough to transform a block, so just copy the bytes into the _InputBuffer
// and return
Buffer.InternalBlockCopy(buffer, offset, _InputBuffer, _InputBufferIndex, count);
_InputBufferIndex += count;
return;
}
}
// If the OutputBuffer has anything in it, write it out
if (_OutputBufferIndex > 0) {
_stream.Write(_OutputBuffer, 0, _OutputBufferIndex);
_OutputBufferIndex = 0;
}
// At this point, either the _InputBuffer is full, empty, or we've already returned.
// If full, let's process it -- we now know the _OutputBuffer is empty
int numOutputBytes;
if (_InputBufferIndex == _InputBlockSize) {
numOutputBytes = _Transform.TransformBlock(_InputBuffer, 0, _InputBlockSize, _OutputBuffer, 0);
// write out the bytes we just got
_stream.Write(_OutputBuffer, 0, numOutputBytes);
// reset the _InputBuffer
_InputBufferIndex = 0;
}
while (bytesToWrite > 0) {
if (bytesToWrite >= _InputBlockSize) {
// We have at least an entire block's worth to transform
// If the transform will handle multiple blocks at once, do that
if (_Transform.CanTransformMultipleBlocks) {
int numWholeBlocks = bytesToWrite / _InputBlockSize;
int numWholeBlocksInBytes = numWholeBlocks * _InputBlockSize;
byte[] _tempOutputBuffer = new byte[numWholeBlocks * _OutputBlockSize];
numOutputBytes = _Transform.TransformBlock(buffer, currentInputIndex, numWholeBlocksInBytes, _tempOutputBuffer, 0);
_stream.Write(_tempOutputBuffer, 0, numOutputBytes);
currentInputIndex += numWholeBlocksInBytes;
bytesToWrite -= numWholeBlocksInBytes;
} else {
// do it the slow way
numOutputBytes = _Transform.TransformBlock(buffer, currentInputIndex, _InputBlockSize, _OutputBuffer, 0);
_stream.Write(_OutputBuffer, 0, numOutputBytes);
currentInputIndex += _InputBlockSize;
bytesToWrite -= _InputBlockSize;
}
} else {
// In this case, we don't have an entire block's worth left, so store it up in the
// input buffer, which by now must be empty.
Buffer.InternalBlockCopy(buffer, currentInputIndex, _InputBuffer, 0, bytesToWrite);
_InputBufferIndex += bytesToWrite;
return;
}
}
return;
}
public void Clear() {
Close();
}
protected override void Dispose(bool disposing) {
try {
if (disposing) {
if (!_finalBlockTransformed) {
FlushFinalBlock();
}
_stream.Close();
// we need to clear all the internal buffers
if (_InputBuffer != null)
Array.Clear(_InputBuffer, 0, _InputBuffer.Length);
if (_OutputBuffer != null)
Array.Clear(_OutputBuffer, 0, _OutputBuffer.Length);
_InputBuffer = null;
_OutputBuffer = null;
}
}
finally {
base.Dispose(disposing);
}
}
// Private methods
private void InitializeBuffer() {
if (_Transform != null) {
_InputBlockSize = _Transform.InputBlockSize;
_InputBuffer = new byte[_InputBlockSize];
_OutputBlockSize = _Transform.OutputBlockSize;
_OutputBuffer = new byte[_OutputBlockSize];
}
}
}
}
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ScalarOps.cs
- WebPartsPersonalization.cs
- DropDownHolder.cs
- Separator.cs
- RelationshipDetailsRow.cs
- TTSVoice.cs
- TextElementEnumerator.cs
- EventInfo.cs
- HtmlTernaryTree.cs
- ChtmlTextWriter.cs
- ToolStripPanelCell.cs
- Attachment.cs
- ReservationCollection.cs
- Enlistment.cs
- Encoder.cs
- TraceLevelStore.cs
- StylusLogic.cs
- GenerateTemporaryTargetAssembly.cs
- Wizard.cs
- GeneralTransform3DTo2D.cs
- URLAttribute.cs
- TileBrush.cs
- StringComparer.cs
- ButtonField.cs
- DBDataPermission.cs
- RadioButtonPopupAdapter.cs
- FixedSOMGroup.cs
- FileDataSourceCache.cs
- StorageMappingFragment.cs
- Panel.cs
- WebPartUtil.cs
- Boolean.cs
- MediaSystem.cs
- ChangePassword.cs
- RowToParametersTransformer.cs
- ProjectionPruner.cs
- HorizontalAlignConverter.cs
- SafeNativeMethods.cs
- Int32AnimationBase.cs
- TreeNode.cs
- FixedStringLookup.cs
- XmlDictionaryWriter.cs
- SqlFunctionAttribute.cs
- FolderNameEditor.cs
- CommunicationException.cs
- ListMarkerSourceInfo.cs
- FileReader.cs
- SplitterCancelEvent.cs
- HtmlInputPassword.cs
- DbDeleteCommandTree.cs
- EnumerableCollectionView.cs
- UpdatePanelTrigger.cs
- XmlArrayItemAttributes.cs
- FormatConvertedBitmap.cs
- unitconverter.cs
- SamlSubjectStatement.cs
- AlgoModule.cs
- DbConnectionPool.cs
- SmiGettersStream.cs
- AppliedDeviceFiltersDialog.cs
- Container.cs
- AstTree.cs
- DataGridViewLinkCell.cs
- WebPermission.cs
- X509SecurityTokenAuthenticator.cs
- RegexCharClass.cs
- UICuesEvent.cs
- ChameleonKey.cs
- InstallerTypeAttribute.cs
- ProcessModule.cs
- Message.cs
- DataGridViewDesigner.cs
- ResourceProviderFactory.cs
- XmlSchemaGroup.cs
- SqlClientPermission.cs
- _FtpDataStream.cs
- ConfigurationSectionGroupCollection.cs
- DocumentSchemaValidator.cs
- HostingEnvironmentException.cs
- CommonDialog.cs
- PasswordBoxAutomationPeer.cs
- TimeZone.cs
- ExpressionDumper.cs
- InvalidCastException.cs
- ConfigXmlText.cs
- SpeakCompletedEventArgs.cs
- MasterPage.cs
- CurrencyManager.cs
- SchemaObjectWriter.cs
- TrackingWorkflowEventArgs.cs
- ProtocolsSection.cs
- WizardPanelChangingEventArgs.cs
- loginstatus.cs
- EncoderReplacementFallback.cs
- Stream.cs
- TargetException.cs
- AbstractDataSvcMapFileLoader.cs
- MailAddress.cs
- ClearTypeHintValidation.cs
- BookmarkNameHelper.cs