14.6 Protect a File Using Symmetric Encryption


Problem

You need to encrypt a file using symmetric encryption.

Solution

First you must instantiate one of the concrete symmetric algorithm classes that extend the System.Security.Cryptography.SymmetricAlgorithm class. Then call the CreateEncryptor or CreateDecryptor method of the SymmetricAlgorithm object to obtain an object that implements the System.Security.Cryptography.ICryptoTransform interface. Use this ICryptoTransform object in conjunction with a System.Security.Cryptography.CryptoStream object to encrypt or decrypt data as you read it from a file ”accessed using a System.IO.FileStream object.

Discussion

The abstract class SymmetricAlgorithm provides a base class from which all concrete symmetric algorithm implementations should derive. The .NET Framework class library includes the four symmetric algorithm implementations listed in Table 14.3; each class is a member of the System.Security.Cryptography namespace. The algorithms with class names ending in CryptoServiceProvider wrap functionality provided by the native Win32 CryptoAPI, whereas those classes whose names end in Managed (currently only RijndaelManaged ) are fully implemented in managed code. The table also shows the encryption key lengths supported by each algorithm; the default key length is in bold. Generally, the longer the encryption key, the harder it is to decrypt ciphertext without the key, but there are also many other factors to consider.

Table 14.3: Symmetric Algorithm Implementations

Algorithm Name

Class Name

Key Lengths (in Bits)

DES

DESCryptoServiceProvider

64

TripleDES or 3DES

TripleDESCryptoServiceProvider

128, 192

RC2

RC2CryptoServiceProvider

40, 48 56, 64, 72, 80, 88, 96, 104, 112, 120, 128

Rijndael

RijndaelManaged

128, 192, 256

Although you can create instances of the symmetric algorithm classes directly, the SymmetricAlgorithm base class is a factory for the concrete implementation classes that derive from it. Calling the static method SymmetricAlgorithm.Create and passing the name of the algorithm that you want will return an object of the specified type. Using this factory approach allows you to write generic code that can work with any symmetric algorithm implementation, as in the following example:

 string algName = "3DES"; SymmetricAlgorithm alg = SymmetricAlgorithm.Create(algName); 
Note  

If you call SymmetricAlgorithm.Create and don't specify an algorithm name, SymmetricAlgorithm will return a RijndaelManaged object. If you specify an invalid value, SymmetricAlgorithm will return null . You can configure new name/class mappings using .NET configuration files. (See the .NET Framework SDK documentation for further details.)

Before you can encrypt data with one of the symmetric algorithm classes, you need a key and an initialization vector . The key is the secret information used to encrypt and decrypt the data. The initialization vector is random data used to seed the encryption algorithm to protect your encrypted data against certain types of cryptographic attack. You must use the same key and initialization vector to both encrypt and decrypt your data ”hence the name symmetric encryption . However, only the key must remain secret; you can store or send the initialization vector with the encrypted data.

The key for each of the SymmetricAlgorithm derived classes is accessible through the Key property, and the initialization vector is accessible through the IV property. The simplest and least error-prone way to generate new keys and initialization vectors is to allow the class to create them for you. After you instantiate a symmetric algorithm object, if you don't explicitly set its Key and IV properties, the object will generate new values automatically the first time you invoke a member that uses the Key and IV values. Once set, the symmetric algorithm object will continue to use the same Key and IV values. To change the values of Key and IV , you can either assign new values directly or call the GenerateKey and GenerateIV methods , which force the symmetric algorithm object to generate new random values.

You can't perform encryption and decryption directly with a symmetric algorithm object. Once you have created and configured the symmetric algorithm object, you must call its CreateEncryptor or CreateDecryptor methods to obtain an object that implements the System.Security.Cryptography.ICryptoTransform interface. You can then use the methods of this ICryptoTransform object to encrypt or decrypt data. However, the ICryptoTransform object requires you to pass data in fixed block sizes and to manually pad the last data block, which will rarely be the correct size .

Although not overly difficult to use, the ICryptoTransform interface isn't particularly friendly, so the .NET Framework includes the System.Security.Cryptography.CryptoStream class. The CryptoStream class, derived from System.IO.Stream , simplifies the encryption and decryption of data read from other Stream objects. This class allows you to encrypt and decrypt data from files and network connections easily using a familiar processing model, and it provides you with all the familiar benefits of Stream -based data access.

The CryptoStream constructor requires three things: an underlying Stream , an ICryptoTransform instance, and a value from the System.Security.Cryptography.CryptoStreamMode enumeration. The CryptoStreamMode value specifies the mode of the new CryptoStream object; valid values are Read and Write . As you call the Read or Write methods of the CryptoStream , the CryptoStream uses the ICryptoTransform instance to encrypt or decrypt the data passing through the CryptoStream . The CryptoStream object ensures the correct block sizes are used for the ICryptoTransform instance.

The configuration of a CryptoStream object provides great flexibility, but it can be a little confusing. Table 14.4 describes the operation of a CryptoStream object based on the CryptoStream mode and the type of ICryptoTransform instance used in the construction of the CryptoStream object.

Table 14.4: Operation of a CryptoStrea m Object

CryptoStream Mode

ICryptoTransform Direction

Description

Read

Encrypt

The underlying Stream contains the source plaintext. Each call to CryptoStream.Read writes ciphertext to an output buffer.

Read

Decrypt

The underlying Stream contains the source ciphertext. Each call to CryptoStream.Read writes plaintext to an output buffer.

Write

Encrypt

Each call to CryptoStream.Write provides plaintext to encrypt. The underlying Stream receives new ciphertext.

Write

Decrypt

Each call to CryptoStream.Write provides ciphertext to decrypt. The underlying Stream receives decrypted plaintext.

The example SymmetricEncryptionExample class shown here demonstrates the use of a SymmetricAlgorithm to Triple DES encrypt a specified file and then decrypt it. The example's Main method (not shown here but available in the accompanying sample code) takes the name of the file to encrypt as a command-line argument. First the Main method generates a Triple DES key and initialization vector to use for encryption and decryption. Then the Main method calls the EncryptFile method, followed by the DecryptFile method, producing two files in the process. The first file has the same name as the source file, but with the prefix encrypted; this file contains the Triple DES encrypted version of the source file. The second file also has the same name as the source file, but this time with the prefix decrypted; this file contains a decrypted version of the encrypted file, which should be the same as the source file.

 using System; using System.IO; using System.Security.Cryptography; public class SymmetricEncryptionExample {     // Main method not shown, see sample code.          // A method to Triple DES encrypt a specified file using the key and iv     // provided.     private static void EncryptFile(string srcFileName,          string destFileName, byte[] key, byte[] iv) {                  // Create streams to access the source and destination files.         Stream srcFile =            new FileStream(srcFileName, FileMode.Open, FileAccess.Read);         Stream destFile =            new FileStream(destFileName, FileMode.Create, FileAccess.Write);                      // Create a new Triple DES algorithm to encrypt the file.         using(SymmetricAlgorithm alg = SymmetricAlgorithm.Create("3DES")){             // Configure the Key and IV properties of the symmetric              // algorithm based on the values provided.             alg.Key = key;             alg.IV = iv;             // Create a CryptoStream to encrypt the contents of the source             // Stream as it is read. Call the CreateEncryptor method of              // the SymmetricAlgorithm to return an encrypting ICryptoTransform              // instance and pass it to the CryptoStream.             CryptoStream cryptoStream = new CryptoStream(srcFile,                                              alg.CreateEncryptor(),                                             CryptoStreamMode.Read);             // Declare a buffer to use for reading data from the source              // file via the CryptoStream and writing to the encrypted file.              int bufferLength;             byte[] buffer = new byte[1024];                          // Read the source file in blocks of 1024 bytes and write the              // encrypted version to the destination file.             do {                 bufferLength = cryptoStream.Read(buffer, 0, 1024);                 destFile.Write(buffer, 0, bufferLength);             } while (bufferLength > 0);                          // Close the Stream resources and clear secret data from              // objects to which we are about to lose reference.             destFile.Flush();             Array.Clear(key,0,key.Length);             Array.Clear(iv,0,iv.Length);             cryptoStream.Clear();                                     cryptoStream.Close();             srcFile.Close();             destFile.Close();         }     }          // A method to decrypt a specified Triple DES encrypted file using the      // key and iv provided.     private static void DecryptFile(string srcFileName,          string destFileName, byte[] key, byte[] iv) {         // Create streams to access the source and destination files.         Stream srcFile =            new FileStream(srcFileName, FileMode.Open, FileAccess.Read);         Stream destFile =            new FileStream(destFileName, FileMode.Create, FileAccess.Write);                      // Create a new Triple DES algorithm to decrypt the file.         using(SymmetricAlgorithm alg = SymmetricAlgorithm.Create("3DES")){             // Configure the Key and IV properties of the symmetric              // algorithm based on the values provided.             alg.Key = key;             alg.IV = iv;                          // Create a CryptoStream to decrypt the contents of the              // encrypted data as it is written. Call the CreateDecryptor             // method of the SymmetricAlgorithm to return a decrypting              // ICryptoTransform instance and pass it to the CryptoStream.             CryptoStream cryptoStream = new CryptoStream(destFile,                                          alg.CreateDecryptor(),                                          CryptoStreamMode.Write);             // Declare a buffer to use for reading data from the encrypted              // file and writing to the decrypted file via the CryptoStream.             int bufferLength;             byte[] buffer = new byte[1024];                          // Read the encrypted file in blocks of 1024 bytes and write              // the plaintext version to the destination file via the              // CryptoStream.             do {                 bufferLength = srcFile.Read(buffer, 0, 1024);                 cryptoStream.Write(buffer, 0, bufferLength);             } while (bufferLength > 0);                          // Close the Stream resources and clear secret data from              // objects to which we are about to lose reference.             cryptoStream.FlushFinalBlock();             Array.Clear(key,0,key.Length);             Array.Clear(iv,0,iv.Length);             cryptoStream.Clear();                                     cryptoStream.Close();             srcFile.Close();             destFile.Close();         }     }  } 



C# Programmer[ap]s Cookbook
C# Programmer[ap]s Cookbook
ISBN: 735619301
EAN: N/A
Year: 2006
Pages: 266

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