Finalization Versus Explicit Destruction via IDisposable

for RuBoard

Finalization Versus Explicit Destruction via IDisposable

Normally, when you are finished using an object in the .NET Framework, the memory allocated by the object will be reclaimed by the Framework's garbage collector on an as-needed basis. However, in the case of cryptographic objects, implicit garbage collection is generally not appropriate. By their very nature, cryptographic objects contain sensitive data, such as secret key values, which must be explicitly destroyed after they are no longer needed.

Every cryptographic object within the .NET Framework implements the IDisposable() interface to support proper disposal of sensitive data. Types within the .NET Framework implement the IDisposable interface to provide a programmable way for user code to indicate that its use of an object is finished. When called, an object's Dispose() method normally releases all the resources that are held by the object and recursively calls the Dispose() method of its parent type. In the case of cryptographic objects, however, simply releasing the internal resources is generally not sufficient, because sensitive data might still remain in the free portion of the managed memory heap. We must additionally destroy the sensitive data before releasing the memory it occupies.

All cryptographic classes that hold sensitive data within the .NET Framework implement a Clear() method to properly erase and dispose of instances of the class. When called, the Clear() method on a cryptographic object will first overwrite all sensitive data within the object with zeros and then release the now-zeroed object so that it can be safely garbage-collected . Listing 31.5 demonstrates how to use Clear() to prepare a cryptographic object for release.

Listing 31.5 Encrypting an On-Disk File to a Second File with Random IV Generation
 public static void EncryptFile(byte[] key, String sourceFile, String destFile) {   // initialize with random key and IV   Rijndael aes = Rijndael.Create();   // set the key to the passed-in arg   aes.Key = key;   // create FileStreams for source and dest   FileStream inStream = new FileStream(sourceFile, FileMode.Open);   FileStream outStream = new FileStream(destFile, FileMode.Create);   // We want to write the IV out to the destFile unencrypted,   // so in this case we can wrap a CryptoStream around the *sourceFile*   // and read encrypted bytes from it   CryptoStream encryptedInStream = new CryptoStream(inStream, aes.CreateEncryptor(), graphics/ccc.gif CryptoStreamMode.Read);   // Write the IV out to the ciphertext file as the first bytes in the file.   outStream.Write(aes.IV, 0, aes.IV.Length);   // Now we're ready to encrypt. Read the bytes from the CryptoStream   // in a loop until there aren't any more (end-of-file), writing to   // the output file as we go. We need a buffer to hold what we're going to   // read, and bytesRead tells us how many bytes in buffer are   //valid ciphertext.   int bytesRead;   byte[] buffer = new byte[1024]; // read 1K at a time   do {       bytesRead = encryptedInStream.Read(buffer,0,1024);       outStream.Write(buffer, 0, bytesRead);   }  while (bytesRead > 0);   // Done!  Close() the streams we used.   inStream.Close();   outStream.Close();   // Clear the Rijndael and CryptoStream objects to zero out   // sensitive data (e.g. key and IV in Rijndael)   encryptedInStream.Clear();   aes.Clear();   // Clearing the buffer is not strictly required since it only holds   // ciphertext, but is good practice also.   Array.Clear(buffer,0,buffer.Length);   return; } 

The code shown in Listing 31.5 is based on the file encryption sample in Listing 30.3, except for the addition of the following lines immediately before the return; statement:

 // Clear the Rijndael and CryptoStream objects to zero out   // sensitive data (e.g. key and IV in Rijndael)   encryptedInStream.Clear();   aes.Clear();   // Clearing the buffer is not strictly required since it only holds   // ciphertext, but is good practice also.   Array.Clear(buffer,0,buffer.Length); 

This code snippet explicitly calls the Clear() methods on the CryptoStream and Rijndael objects created within the EncryptFile method, thus making them safe to free and release to the garbage collector. Notice that we also explicitly zero the contents of the internal buffer variable; because buffer contains only ciphertext, it is not strictly necessary to zero out its contents, but it is good practice to do so.

CAUTION

It is not sufficient to simply force a garbage collection after you have finished using a cryptographic object, you must explicitly call the Clear() method on the object to zero out and release all sensitive data within the object. The garbage collection does not zero the contents of the collected objects but simply marks the memory as available for reallocation. Thus, the data contained within a garbage collected object may still be present in the memory heap (in unallocated memory); in the case of a cryptographic object, that data could contain sensitive information, such as key data or a block of plain text. Whenever you finish using a cryptographic object, follow best practices and call the object's Clear() method before releasing it.

Additionally, as previously noted, the Clear() methods on .NET Framework cryptographic objects make it easier for conscientious developers to properly dispose of sensitive information, but they are not cure- alls . Any variable you create that subsequently holds sensitive information, especially encryption or decryption keys, must be explicitly zeroed by the developer before the last reference to the object is released.


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