Recipe17.2.EncryptingDecrypting a String


Recipe 17.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 CryptoString class shown in Example 17-5 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.

Example 17-5. CryptoString class

 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.         using (MemoryStream memStream = new                  MemoryStream(originalStrAsBytes.Length))         {             using (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.                 using (ICryptoTransform rdTransform =                        rijndael.CreateEncryptor((byte[])savedKey.                        Clone( ),(byte[])savedIV.Clone( )))                 {                     using (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( );                     }                 }             }         }         // 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];         using (RijndaelManaged rijndael = new RijndaelManaged( ))         {             using (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.                 using (ICryptoTransform rdTransform =                      rijndael.CreateDecryptor((byte[])savedKey.                      Clone( ),(byte[])savedIV.Clone( )))                 {                     using (CryptoStream cryptoStream = new CryptoStream(memStream,                      rdTransform, CryptoStreamMode.Read))                      {                      // Read in decrypted string as a byte[].                      cryptoStream.Read(initialText, 0, initialText.Length);                      }                 }             }         }         // Convert byte[] to string.         string decryptedStr = Encoding.ASCII.GetString(initialText);         return (decryptedStr);     } } 

Discussion

The CryptoString 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 both the encryption and decryption methods to encrypt and decrypt 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.

Two methods in the CryptoString class, RdGenerateSecretKey and RdGenerateSecretInitVector, are used to generate a secret key and initialization vector when none exists. 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. 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: {0}", 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== 

Note that your output may differ since you will be using a different key and IV value. 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: {0}", decryptedString); 

This method displays:

 decryptedString: MyPassword 

There does not seem to be any problem 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 17.3; see the "System.Cryptography Namespace," "MemoryStream Class," "ICryptoTransform Interface," 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