Recipe17.3.Encrypting and Decrypting a File


Recipe 17.3. Encrypting and Decrypting a File

Problem

You have sensitive information that must be encrypted before it is written to a file that might be in a nonsecure area. This information must also be decrypted before it is read back in to the application.

Solution

Use multiple cryptography providers and write the data to a file in encrypted format. This is accomplished in the following class, which has a constructor that expects an instance of the System.Security.Cryptography.SymmetricAlgorithm class and a path for the file. The SymmetricAlgorithm class is an abstract base class for all cryptographic providers in .NET, so you can be reasonably assured that this class could be extended to cover all of them. This example implements support for TripleDES and Rijndael. It is easily be extended for Data Encryption Standard (DES) and RC2, which are also provided by the Framework.

The following namespaces are needed for this solution:

 using System; using System.Text; using System.IO; using System.Security.Cryptography; 

The class SecretFile (implemented in this recipe) can be used for TripleDES as shown:

 // Use TripleDES. using (TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider( )) {     SecretFile secretTDESFile = new SecretFile(tdes,"tdestext.secret");     string encrypt = "My TDES Secret Data!";     Console.WriteLine("Writing secret data: {0}",encrypt);     secretTDESFile.SaveSensitiveData(encrypt);     // Save for storage to read file.     byte [] key = secretTDESFile.Key;     byte [] IV = secretTDESFile.IV;     string decrypt = secretTDESFile.ReadSensitiveData( );     Console.WriteLine("Read secret data: {0}",decrypt); } 

To use SecretFile with Rijndael, just substitute the provider in the constructor like this:

 // Use Rijndael. using (RijndaelManaged rdProvider = new RijndaelManaged( )) {     SecretFile secretRDFile = new SecretFile(rdProvider,"rdtext.secret");     string encrypt = "My Rijndael Secret Data!";     Console.WriteLine("Writing secret data: {0}",encrypt);     secretRDFile.SaveSensitiveData(encrypt);     // Save for storage to read file.     byte [] key = secretRDFile.Key;     byte [] IV = secretRDFile.IV;     string decrypt = secretRDFile.ReadSensitiveData( );     Console.WriteLine("Read secret data: {0}",decrypt); } 

Example 17-6 shows the implementation of SecretFile.

Example 17-6. SecretFile class

 public class SecretFile {     private byte[] savedKey = null;     private byte[] savedIV = null;     private SymmetricAlgorithm symmetricAlgorithm;     string path;     public byte[] Key     {         get { return savedKey; }         set { savedKey = value; }     }     public byte[] IV     {         get { return savedIV; }         set { savedIV = value; }     }     public SecretFile(SymmetricAlgorithm algorithm, string fileName)     {         symmetricAlgorithm = algorithm;         path = fileName;     }     public void SaveSensitiveData(string sensitiveData)     {         // Encode data string to be stored in encrypted file.         byte[] encodedData = Encoding.Unicode.GetBytes(sensitiveData);         // Create FileStream and crypto service provider objects.         using (FileStream fileStream = new FileStream(path,                                                FileMode.Create,                                                FileAccess.Write))         {             // Generate and save secret key and init vector.             GenerateSecretKey( );             GenerateSecretInitVector( );             // Create crypto transform and stream objects.             using (ICryptoTransform transform =                         symmetricAlgorithm.CreateEncryptor(savedKey,                         savedIV))             {                 using (CryptoStream cryptoStream =               new CryptoStream(fileStream, transform, CryptoStreamMode.Write))                 {                     // Write encrypted data to the file.                     cryptoStream.Write(encodedData, 0, encodedData.Length);                 }             }         }     }     public string ReadSensitiveData( )     {         string decrypted = "";         // Create file stream to read encrypted file back.         using (FileStream fileStream = new FileStream(path,                                                FileMode.Open,                                                FileAccess.Read))         {             // Print out the contents of the encrypted file.             using (BinaryReader binReader = new BinaryReader(fileStream))             {                 Console.WriteLine("---------- Encrypted Data ---------");                 int count = (Convert.ToInt32(binReader.BaseStream.Length));                 byte [] bytes = binReader.ReadBytes(count);                 char [] array = Encoding.Unicode.GetChars(bytes);                 string encdata = new string(array);                 Console.WriteLine(encdata);                 Console.WriteLine("---------- Encrypted Data ---------\r\n");                 // Reset the file stream.                 fileStream.Seek(0,SeekOrigin.Begin);                 // Create decryptor.                 using (ICryptoTransform transform =                     symmetricAlgorithm.CreateDecryptor(savedKey, savedIV))                 {                     using (CryptoStream cryptoStream = new CryptoStream(fileStream,                                                      transform,                                                      CryptoStreamMode.Read))                     {                         // Print out the contents of the decrypted file.                         StreamReader srDecrypted = new StreamReader(cryptoStream,                                                     new UnicodeEncoding( ));                         Console.WriteLine("---------- Decrypted Data ---------");                         decrypted = srDecrypted.ReadToEnd( );                         Console.WriteLine(decrypted);                         Console.WriteLine("---------- Decrypted Data ---------");                     }                 }             }         }         return decrypted;     }     private void GenerateSecretKey( )     {         if (null != (symmetricAlgorithm as TripleDESCryptoServiceProvider))         {             TripleDESCryptoServiceProvider tdes;             tdes = symmetricAlgorithm as TripleDESCryptoServiceProvider;             tdes.KeySize = 192; // Maximum key size             tdes.GenerateKey( );             savedKey = tdes.Key;         }         else if (null != (symmetricAlgorithm as RijndaelManaged))         {             RijndaelManaged rdProvider;             rdProvider = symmetricAlgorithm as RijndaelManaged;             rdProvider.KeySize = 256; // Maximum key size             rdProvider.GenerateKey( );             savedKey = rdProvider.Key;         }     }     private void GenerateSecretInitVector( )     {         if (null != (symmetricAlgorithm as TripleDESCryptoServiceProvider))         {             TripleDESCryptoServiceProvider tdes;             tdes = symmetricAlgorithm as TripleDESCryptoServiceProvider;             tdes.GenerateIV( );             savedIV = tdes.IV;         }         else if (null != (symmetricAlgorithm as RijndaelManaged))         {             RijndaelManaged rdProvider;             rdProvider = symmetricAlgorithm as RijndaelManaged;             rdProvider.GenerateIV( );             savedIV = rdProvider.IV;         }     } 

If the SaveSensitiveData method is used to save the following text to a file:

 This is a test This is sensitive data! 

the ReadSensitiveData method will display the following information from this same file:

 ---------- Encrypted Data -------- ???????????????????????????????????????? ---------- Encrypted Data -------- ---------- Decrypted Data --------- This is a test This is sensitive data! ---------- Decrypted Data --------- 

Discussion

Encrypting data is essential to many applications, especially ones that store information in easily accessible locations. Once data is encrypted, a decryption scheme is required to restore the data back to an unencrypted form without losing any information. The same underlying algorithms can be used to authenticate the source of a file or message.

The encryption schemes used in this recipe are TripleDES and Rijndael. The reasons for using Triple DES are:

  • TripleDES employs symmetric encryption, meaning that a single private key is used to encrypt and decrypt data. This process allows much faster encryption and decryption, especially as the streams of data become larger.

  • TripleDES encryption is much harder to crack than the older DES encryption.

  • If you wish to use another type of encryption, this recipe can be easily converted using any provider derived from the SymmetricAlgorithm class.

The main drawback to TripleDES is that both the sender and receiver must use the same key and initialization vector (IV) in order to encrypt and decrypt the data successfully. If you wish to have an even more secure encryption scheme, use the Rijndael scheme. This type of encryption scheme is highly regarded as a solid encryption scheme, since it is fast and can use larger key sizes than TripleDES. However, it is still a symmetric cryptosystem, which means that it relies on shared secrets. Use an asymmetric cryptosystem, such as RSA or DSA, for a cryptosystem that uses shared public keys with private keys that are never shared between parties.

See Also

See the "SymmetricAlgorithm Class," "TripleDESCryptoServiceProvider Class," and "RijndaelManaged Class" topics in the MSDN documentation.



C# Cookbook
Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More
ISBN: 0596003943
EAN: 2147483647
Year: 2004
Pages: 424

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