Recipe 14.2 EncryptingDecrypting a String

Recipe 14.2 Encrypting/ Decrypting a String

Problem

You have a string you want to be able to encrypt and decryptperhaps a password or software keywhich will be stored in some form accessible by users, such as in a file, the registry, or even a field, that may be open to attack from malicious code.

Solution

Encrypting the string will prevent users from being able to read and decipher the information. The following class, CryptoString , contains two static methods to encrypt and decrypt a string and two static properties to retrieve the generated key and inititialization vector (IVa random number used as a starting point to encrypt data) after encryption has occurred:

 using System; using System.Security.Cryptography; public sealed class CryptoString {     private CryptoString( ) {}     private static byte[] savedKey = null;     private static byte[] savedIV = null;      public static byte[] Key     {         get { return savedKey; }         set { savedKey = value; }     }      public static byte[] IV     {         get { return savedIV; }         set { savedIV = value; }     }     private static void RdGenerateSecretKey(RijndaelManaged rdProvider)     {         if (savedKey == null)         {             rdProvider.KeySize = 256;             rdProvider.GenerateKey( );             savedKey = rdProvider.Key;         }     }     private static void RdGenerateSecretInitVector(RijndaelManaged rdProvider)     {         if (savedIV == null)         {             rdProvider.GenerateIV( );             savedIV = rdProvider.IV;         }     }     public static string Encrypt(string originalStr)     {         // Encode data string to be stored in memory         byte[] originalStrAsBytes = Encoding.ASCII.GetBytes(originalStr);         byte[] originalBytes = {};         // Create MemoryStream to contain output         MemoryStream memStream = new MemoryStream(originalStrAsBytes.Length);         RijndaelManaged rijndael = new RijndaelManaged( );         // Generate and save secret key and init vector         RdGenerateSecretKey(rijndael);         RdGenerateSecretInitVector(rijndael);         if (savedKey == null  savedIV == null)         {             throw (new NullReferenceException(                     "savedKey and savedIV must be non-null."));         }         // Create encryptor, and stream objects         ICryptoTransform rdTransform = rijndael.CreateEncryptor((byte[])savedKey.                             Clone( ),(byte[])savedIV.Clone( ));         CryptoStream cryptoStream = new CryptoStream(memStream, rdTransform,                              CryptoStreamMode.Write);         // Write encrypted data to the MemoryStream         cryptoStream.Write(originalStrAsBytes, 0, originalStrAsBytes.Length);         cryptoStream.FlushFinalBlock( );         originalBytes = memStream.ToArray( );         // Release all resources         memStream.Close( );         cryptoStream.Close( );         rdTransform.Dispose( );         rijndael.Clear( );         // Convert encrypted string         string encryptedStr = Convert.ToBase64String(originalBytes);         return (encryptedStr);     }     public static string Decrypt(string encryptedStr)     {         // Unconvert encrypted string         byte[] encryptedStrAsBytes = Convert.FromBase64String(encryptedStr);         byte[] initialText = new Byte[encryptedStrAsBytes.Length];         RijndaelManaged rijndael = new RijndaelManaged( );         MemoryStream memStream = new MemoryStream(encryptedStrAsBytes);         if (savedKey == null  savedIV == null)         {             throw (new NullReferenceException(                     "savedKey and savedIV must be non-null."));         }         // Create decryptor, and stream objects         ICryptoTransform rdTransform = rijndael.CreateDecryptor((byte[])savedKey.                             Clone( ),(byte[])savedIV.Clone( ));         CryptoStream cryptoStream = new CryptoStream(memStream, rdTransform,                              CryptoStreamMode.Read);         // Read in decrypted string as a byte[]         cryptoStream.Read(initialText, 0, initialText.Length);         // Release all resources         memStream.Close( );         cryptoStream.Close( );         rdTransform.Dispose( );         rijndael.Clear( );         // Convert byte[] to string         string decryptedStr = Encoding.ASCII.GetString(initialText);         return (decryptedStr);     } } 

Discussion

The CryptoString class follows a singleton design pattern. This class contains only static members , except for the private instance constructor, which prevents anyone from directly creating an object from this class.

This class uses the Rijndael algorithm to encrypt and decrypt a string. This algorithm is found in the System.Security.Cryptography.RijndaelManaged class. This algorithm requires a secret key and an initialization vector; both are byte arrays. A random secret key can be generated for you by calling the GenerateKey method on the RijndaelManaged class. This method accepts no parameters and returns void . The generated key is placed in the Key property of the RijndaelManaged class. The GenerateIV method generates a random initialization vector and places this vector in the IV property of the RijndaelManaged class.

The byte array values in the Key and IV properties must be stored for later use and not modified. This is due to the nature of private-key encryption classes, such as RijndaelManaged . The Key and IV values must be used by both the encryption and decryption routines to successfully encrypt and decrypt data.

The SavedKey and SavedIV private static fields contain the secret key and initialization vector, respectively. The secret key is used by the encryption and decryption methods to encrypt and decrypt data. This key must be used by both the encryption and decryption methods in order to successfully encrypt and then decrypt the data. This is why there are public properties for these values, so they can be stored somewhere secure for later use. This means that any strings encrypted by this object must be decrypted by this object. The initialization vector is used to prevent anyone from attempting to decipher the secret key.

There are two methods in the CryptoString class, RdGenerateSecretKey and RdGenerateSecretInitVector , that are used to generate a secret key and initialization vector, when none exist. The RdGenerateSecretKey method generates the secret key, which is placed in the SavedKey field. Likewise, the RdGenerateSecretInitVector generates the initialization vector, which is placed in the SavedIV field. There is only one key and one IV generated for this class. This enables the encryption and decryption routines to have access to the same key and IV information at all times.

The Encrypt and Decrypt methods of the CryptoString class do the actual work of encrypting and decrypting a string, respectively. The Encrypt method accepts a string that you want to encrypt and returns an encrypted string. The following code calls this method and passes in a string to be encrypted:

 string encryptedString = CryptoString.Encrypt("MyPassword"); Console.WriteLine("encryptedString: " + encryptedString); // get the key and IV used so you can decrypt it later byte [] key = CryptoString.Key; byte [] IV = CryptoString.IV; 

Once the string is encrypted, the key and IV are stored for later decryption. This method displays:

 encryptedString: Ah4vkmVKpwMYRT97Q8cVgQ== 

The following code sets the key and IV used to encrypt the string, then calls the Decrypt method to decrypt the previously encrypted string:

 CryptoString.Key = key; CryptoString.IV = IV; string decryptedString = CryptoString.Decrypt(encryptedString); Console.WriteLine("decryptedString: " + decryptedString); 

This method displays:

 decryptedString: MyPassword 

There does not seem to be any problems with using escape sequences such as \r , \n , \r\n , or \t in the string to be encrypted. In addition, using a quoted string literal, with or without escaped characters , works without a problem:

 @"MyPassword" 

See Also

See Recipe 3.32 ; see the "System.Cryptography Namespace," "MemoryStream Class," "ICryptoTransform Interface," and "RijndaelManaged Class" topics in the MSDN documentation.



C# Cookbook
C# 3.0 Cookbook
ISBN: 059651610X
EAN: 2147483647
Year: 2003
Pages: 315

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