Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More

Recipe 17.4. Cleaning up Cryptography Information

Problem

You will be using the cryptography classes in the FCL to encrypt and/or decrypt data. In doing so, you want to make sure that no data (e.g., seed values or keys) is left in memory for longer than you are using the cryptography classes. Hackers can sometimes find this information in memory and use it to break your encryption or, worse, to break your encryption, modify the data, and then reencrypt the data and pass it on to your application.

Solution

In order to clear out the key and initialization vector (or seed), you need to call the Clear method on whichever SymmetricAlgorithm- or AsymmetricAlgorithm-derived class you are using. Clear reinitializes the Key and IV properties, preventing them from being found in memory. This is done after saving the key and IV so that you can decrypt later. Example 17-7 encodes a string, then cleans up immediately afterward to provide the smallest window possible for potential attackers.

Example 17-7. Cleaning up cryptography information

using System; using System.Text; using System.IO; using System.Security.Cryptography; string originalStr = "SuperSecret information"; // Encode data string to be stored in memory. byte[] originalStrAsBytes = Encoding.ASCII.GetBytes(originalStr); // Create MemoryStream to contain output. MemoryStream memStream = new MemoryStream(originalStrAsBytes.Length); RijndaelManaged rijndael = new RijndaelManaged( ); // Generate secret key and init vector. rijndael.KeySize = 256; rijndael.GenerateKey( ); rijndael.GenerateIV( ); // Save the key and IV for later decryption. byte [] key = rijndael.Key; byte [] IV = rijndael.IV; // Create encryptor, and stream objects. ICryptoTransform transform = rijndael.CreateEncryptor(rijndael.Key, rijndael.IV); CryptoStream cryptoStream = new CryptoStream(memStream, transform, CryptoStreamMode.Write); // Write encrypted data to the MemoryStream. cryptoStream.Write(originalStrAsBytes, 0, originalStrAsBytes.Length); cryptoStream.FlushFinalBlock( ); // Release all resources as soon as we are done with them // to prevent retaining any information in memory. memStream.Close( ); cryptoStream.Close( ); transform.Dispose( ); // This clear statement regens both the key and the init vector so that // what is left in memory is no longer the values you used to encrypt with. rijndael.Clear( );

You can also make your life a little easier by taking advantage of the using statement, instead of having to remember to manually call each of the Close methods individually. This code block shows how to use the using statement:

public static void CleanUpCryptoWithUsing() { string originalStr = "SuperSecret information"; // Encode data string to be stored in memory. byte[] originalStrAsBytes = Encoding.ASCII.GetBytes(originalStr); byte[] originalBytes = { }; // Create MemoryStream to contain output. using (MemoryStream memStream = new MemoryStream(originalStrAsBytes.Length)) { using (RijndaelManaged rijndael = new RijndaelManaged()) { // Generate secret key and init vector. rijndael.KeySize = 256; rijndael.GenerateKey(); rijndael.GenerateIV(); // Save off the key and IV for later decryption. byte[] key = rijndael.Key; byte[] IV = rijndael.IV; // Create encryptor, and stream objects. using (ICryptoTransform transform = rijndael.CreateEncryptor(rijndael.Key, rijndael.IV)) { using (CryptoStream cryptoStream = new CryptoStream(memStream, transform, CryptoStreamMode.Write)) { // Write encrypted data to the MemoryStream. cryptoStream.Write(originalStrAsBytes, 0, originalStrAsBytes.Length); cryptoStream.FlushFinalBlock(); } } } } }

Discussion

To make sure your data is safe, you need to close the MemoryStream and CryptoStream objects as soon as possible, as well as calling Dispose on the ICryptoTransform implementation to clear out any resources used in this encryption. The using statement makes this process much easier, makes your code easier to read, and leads to fewer programming mistakes.

See Also

See the "SymmetricAlgorithm.Clear Method" and "AsymmetricAlgorithm.Clear Method" topics in the MSDN documentation.

Категории