Operating on Streams: CryptoStreams and ICryptoTransforms

for RuBoard

Operating on Streams: CryptoStreams and ICryptoTransforms

A common scenario for developers is the application of cryptographic transforms to a stream of binary data, such as encrypting data about to be written to an on-disk file or a network connection. The .NET Framework cryptography classes make it very easy to perform these sorts of operations using the CryptoStream class and objects implementing the ICryptoTransform interface. We first describe the ICryptoTransform model block transforms and then show how these transforms can be "wrapped" around any stream in the .NET Framework using the CryptoStream class.

Figure 30.10 shows the basic model of an ICryptoTransform . An ICryptoTransform represents any blockwise mathematical transformation, such as encryption or decryption by a symmetric key cipher. By "blockwise," we mean that the transform takes in input blocks of fixed size and turns them into output blocks of fixed size . All of the secret key ciphers supported natively in the .NET Framework are block ciphers that operate this way: DES, Triple DES, and RC2 operate on input blocks of 8 bytes (producing 8 bytes of output), and Rijndael/AES operates on input blocks of 16 bytes (producing 16 bytes of output). Although it has "crypto" in its name , the transformation represented by an ICryptoTransform need not be an encryption or decryption function. Within the .NET Framework, we also model operations such as cryptographic hash functions, Base64 encoding and decoding, and even specialized padding and formatting operations, such as PKCS#1 padding ICryptoTransforms .

Figure 30.10. The ICryptoTransform interface.

graphics/30fig10.gif

Every ICryptoTransform exposes four read-only properties, detailed in Table 30.1. These properties describe how the transform operates and under what conditions the object can be reused. Because ICryptoTransforms are most often used in conjunction with the CryptoStream class, these properties exist primarily to help CryptoStream tailor itself to the particular transform. You will only need to deal with these properties if you call an ICryptoTransform directly or implement a new ICryptoTransform .

Table 30.1. ICryptoTransform Properties
Property Type Description
InputBlockSize Integer Size of input block in bytes.
OutputBlockSize Integer Size of output block in bytes.
CanTransformMultipleBlocks Boolean If true , multiple blocks of input data can be passed to the TransformBlock method in a single call.
CanReuseTransform Boolean If true , the transform can be reused on another data stream after the TransformFinalBlock method has been called.

In addition to its four properties, each ICryptoTransform implements two methods ” TransformBlock and TransformFinalBlock . These two methods perform the actual cryptographic transformation represented by the ICryptoTransform . The difference between the two methods is that the TransformFinalBlock method signals that the last block of data from the input stream is being processed and that the ICryptoTransform should do whatever final processing is required to finish the stream. (For example, depending on the length of the input, the last block to be transformed may be a "short" block and not contain a full InputBlockSize 's worth of data, thus necessitating that some padding data be added.)

All objects that represent secret key ciphers include methods for creating related ICryptoTransform objects. In particular, every SymmetricAlgorithm includes two methods, CreateEncryptor() and CreateDecryptor() , that create encryption and decryption ICryptoTransforms from the key material, initialization vector, and operation modes specified by the object. Every HashAlgorithm also implements the ICryptoTransform interface, as do encoding and decoding objects such as ToBase64Transform and FromBase64Transform (which encode and decode binary data as ASCII strings in the Base64 format).

Now that we know an ICryptoTransform represents a blockwise cryptographic transformation, how can the ICryptoTransform be used to transform a stream of data? Transformations on streams are performed by "wrapping" an ICryptoTransform around the input stream using the CryptoStream class. A CryptoStream is itself a stream, but its contents are generated by applying an ICryptoTransform block-by-block to other input data. Figure 30.11 graphically depicts the flow of data read from a CryptoStream in read mode.

Figure 30.11. How CryptoStream works in read mode.

graphics/30fig11.gif

To create a CryptoStream , you must specify three arguments ”the underlying stream, the ICryptoTransform to be applied to the input data, and an enum value, either CryptoStreamMode.Read or CryptoStreamMode.Write , to indicate whether the CryptoStream is going to be used in read mode or write mode. A CryptoStream must be used exclusively in either read mode or write mode, and its behavior changes depending on the mode in which it is operating. In read mode, reading bytes from a CryptoStream causes data to be read from the underlying stream, transformed by the specified ICryptoTransform , and then returned as the results of the read request. In write mode, writing bytes to the CryptoStream causes that data to be transformed by the specified ICryptoTransform and then written to the underlying stream. In both cases, the CryptoStream will buffer input and output bytes as necessary to use the ICryptoTransform properly.

CryptoStreams are pretty easy to use, but keep in mind the following requirements when using them. First, the underlying stream inside a CryptoStream must be a descendant of the System.IO.Stream class, which is the base class for all stream-like classes in the .NET Framework. Additionally, the subclass of System.IO.Stream must support reading if the CryptoStream is in read mode (and writing if the CryptoStream is in write mode). CryptoStreams are not seek-able; you cannot read or set the Length or Position of a CryptoStream , because the class only supports sequential access to the underlying data. Finally, note that whether a CryptoStream is in read or write mode is independent of whether its ICryptoTransform is performing an encryption or decryption operation. We tend to think of stored data as being encrypted and then naturally associate "read from file" with decryption and "write to file" with encryption, but, as you will see in the examples in the next section, all four combinations can arise in your programs.

NOTE

A Stream class supports reading if the value of its CanRead property is true . Similarly, a Stream supports writing if the value of its CanWrite property is true .


for RuBoard


. NET Framework Security
.NET Framework Security
ISBN: 067232184X
EAN: 2147483647
Year: 2000
Pages: 235

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net