Chapter 7 - Relieving Cryptography Complexity

Introduction

How secret are your secrets? We all know how important it is to encrypt information that is sensitive, whether it is stored in a database or a disk file, passed over the network (especially the Internet), or even sitting around in memory. Handing over a list of your customers' credit card numbers to some geek sitting in his bedroom hacking your online store is not a great way to build customer confidence. Neither is allowing some disenfranchised administrator to leave your company with a plain-text copy of all your trading partners' network passwords.

The trouble is that writing all that extra code from scratch to perform reliable and secure encryption is complicated and soaks up valuable development time. Even the names of the encryption algorithms are impenetrable, such as AES, 3DES, and RC5. And when it comes to hashing algorithms, there's even more of an assortment. How do you implement routines to use the HMAC, MD5, RIPEMD, and SHA algorithms?

The Microsoft® .NET Framework provides a range of managed code hashing and encryption mechanisms, but you still need to write a good deal of code to use them. Thankfully, the Cryptography Application Block makes it all very much easier. Like all of the other application blocks in Enterprise Library, the Cryptography block is completely configurable and manageable, and offers a wide range of hashing and encryption options using many of the common (and some not so common) algorithms.

What Does the Cryptography Block Do?

The Cryptography block provides mechanisms to perform two basic activities: symmetric encryption/decryption of data, and creating hash values from data. It contains a range of providers that make use of the platform functions for a range of encryption and hashing algorithms. These providers have a simple API that makes it easy to perform common actions, without requiring you to be familiar with the individual algorithms or the process of interacting with the platform functionality.

A Secret Shared

One important point you must be aware of is that there are two basic types of encryption: symmetric (or shared key) encryption, and asymmetric (or public key) encryption. The Cryptography block supports only symmetric encryption. The patterns & practices guide "Data Confidentiality" at http://msdn.microsoft.com/en-us/library/aa480570.aspx provides an overview of both types of encryption and lists the factors you should consider when using encryption.

Is a secret still secret when you tell it to somebody else? When using symmetric encryption, you don’t have a choice. Unlike asymmetric encryption, which uses different public and private keys, symmetric encryption uses a single key to both encrypt and decrypt the data. Therefore, you must share the encryption key with the other party so that they (or it, in the case of code) can decrypt the data.

In general, this means that the key should be long and complex (the name of your dog is not a great example of an encryption key). Depending on the algorithm you choose, this key will usually be a minimum of 128 bits—the configuration tools in Enterprise Library can generate random keys for you, as you'll see in the section "Configuring Cryptographic Providers" later in this chapter. Alternatively, you can configure the encryption providers to use your existing keys.

Making a Hash of It

Hashing is useful when you need to store a value or data in a way that hides the original content with no option of reconstructing the original content. An obvious example is when storing passwords in a database. Of course, the whole point of creating a hash is to prevent the initial value from being readable; thus, the process is usually described as a one-way hashing function. Therefore, as you can’t get the original value back again, you can only use hashing where it is possible to compare hashed values. This is why many systems allow users only to reset (but not retrieve) their passwords; because the system itself has no way to retrieve the original password text.

In the case of stored passwords, the process is easy. You just hash the password the user provides when they log in and compare it with the hash stored in your database or repository. Just be aware that you cannot provide a forgotten password function that allows users to retrieve a password. Sending them the hashed value would not be of any help at all.

Other examples for using hashing are to compare two long string values or large objects. Hashing effectively generates a unique key for such a value or object that is considerably smaller, or shorter, than the value itself.

How Does the Cryptography Block Manage Encryption Keys?

The keys required for both encryption and decryption are stored in separate files, one for each key, on your machine. The full physical path and name of each key file is stored in the configuration of your application. If you move your application or key files, you must update this path.

One vitally important issue you must be aware of when using encryption (both symmetric providers and some hashing algorithms) is that, if a malicious user or attacker obtains access to your keys, they can use them to decrypt your data. Therefore, to protect the keys, the key files are encrypted automatically using the Windows® Data Protection application programming interface (DPAPI), which relies on either a machine key or a user key that is auto-generated by the operating system. If you lose a key file, or if a malicious user or attacker damages it, you will be unable to decrypt the data you encrypted with that key.

Therefore, ensure that you protect your key files from malicious access, and keep backup copies. In particular, protect your keys with access control lists (ACL) that grant only the necessary permissions to the identities that require access to the key file, and avoid allowing remote debugging if the computer runs in a high-risk environment (such as a Web server that allows anonymous access).

For more information on DPAPI, and a description of how it works, see "Windows Data Protection" at http://msdn.microsoft.com/en-us/library/ms995355.aspx.

How Does the Cryptography Block Integrate with Other Blocks?

The Cryptography block integrates with the Caching block, where it can be used to encrypt cached data. When you add a symmetric storage encryption provider to the Caching block, it automatically adds the Cryptography block to your application configuration.

The Security block uses the Caching block to store credentials. When you add a caching store provider to a security cache for the Security block, you can configure that caching store provider to use one of your configured cache managers. If that cache manager uses a persistent backing store, you should ensure that you use a symmetric storage encryption provider for that cache manager.

How Do I Use the Cryptography Block?

Like all of the Enterprise Library application blocks, you start by configuring your application to use the block, as demonstrated in Chapter 1, "Introduction." Then you add one or more hash algorithm providers and one or more symmetric encryption providers, depending on the requirements of your application. For each of the providers that you add, you select a specific cryptographic provider (algorithm type) and set the relevant properties for each provider. If none of the built-in hash and symmetric encryption providers meets your requirements, you can create custom providers and add these to your application configuration.

After you add the hash algorithm providers and symmetric encryption providers you want to use to your configuration, you can specify which of each of these is the default—the one that the block will use if you don't specify a provider by name in your application code. You just use the drop-down lists for the DefaultHashProvider and DefaultSymmetricCryptoProvider properties of the Cryptography Application Block node to select the default providers.

Of course, as part of the configuration task, you still need to decide which algorithms to use. For a Hash Algorithm Provider, you can specify if the provider will use a SALT value (a random string pre-pended to the plain-text before hashing to improve the security of the algorithm). In addition, for some of the hash algorithms, you can specify or generate a key for the algorithm. Other providers, such as SHA and MD5, do not require a key. As a general recommendation, you should aim to use at minimum the SHA256 algorithm for hashing, and preferably a more robust version such as SHA384 or SHA512.

You can use two different types of Symmetric Encryption Provider in the Cryptography block (in addition to custom providers that you create). You can choose the DPAPI provider, or one of the well-known symmetric algorithms such as AES or 3DES. As a general recommendation, you should aim to use the AES (Rijndael) algorithm for encryption.

Ff953194.note(en-us,PandP.50).gifNote:
Comprehensive information about the many different encryption and hashing algorithms is contained in the Handbook of Applied Cryptography (Menezes, Alfred J., Paul C. van Oorschot and Scott A. Vanstone, CRC Press, October 1996, ISBN: 0-8493-8523-7). See http://www.cacr.math.uwaterloo.ca/hac/ for more information. You will also find a list of publications that focus on cryptography at "Additional Documentation on Cryptography" (http://msdn.microsoft.com/en-us/library/aa375543(VS.85).aspx).

Configuring Cryptographic Providers

In addition to the obvious properties for each cryptographic provider you add to your configuration, such as the name, some providers require you to specify an encryption key. If you already have a DPAPI-encrypted key file for the selected algorithm type, you can use this. Alternatively, you can copy an existing plain text value of the appropriate size and use that as the key value. The third approach is to allow the Enterprise Library configuration to generate a new key for you.

When you add a provider that requires a key to your configuration, the configuration tool starts the Cryptographic Key Wizard. This makes it easy to select or create the key you need and save it to a file and to set the appropriate values in the configuration. The only page you may find confusing is the final one where you must specify either Machine mode or User mode access to the key.

You should select Machine mode if your application runs on its own dedicated server that is not shared with other applications, or when you have multiple applications that run on the same server and you want those applications to be able to share sensitive information.

Select User mode if you run your application in a shared hosting environment and you want to make sure that your application's sensitive data is not accessible to other applications on the server. In this situation, each application should run under a separate identity, and the resources for the application—such as files and databases—should be restricted to that identity.

If you add a DPAPI symmetric cryptography provider to your list of symmetric providers, you can specify the Protection Scope as either CurrentUser or LocalMachine. Current user means that DPAPI uses a loaded user profile to generate the key, and only that user account can decrypt the encrypted data. Local machine means that any code running on the machine has access to the protected key, and can decrypt any secret encrypted in the same mode.

Adding the Required References

To use the Cryptography block features in your application, you must reference the required assemblies and then instantiate the objects you want to use in your code. In addition to the Enterprise Library assemblies you require in every Enterprise Library project (listed in Chapter 1, "Introduction"), you should reference or add to your bin folder the following assemblies:

  • Microsoft.Practices.EnterpriseLibrary.Security.Cryptography.dll
  • Microsoft.Practices.EnterpriseLibrary.Security.Caching.dll

To make it easier to use the objects in the Cryptography block, you can add references to the relevant namespaces to your project. Then you are ready to write some code. The following sections demonstrate the tasks you can accomplish, and provide more details about how the block helps you to implement a common and reusable strategy for cryptography.

However, before you start to use the objects in the block, you must resolve an instance of the CryptographyManager class. This class exposes the API that you interact with to use the cryptography providers (symmetric and hash providers) in your code. The simplest approach is to use the GetInstance method of the Enterprise Library container, as shown here.

// Resolve the default CryptographyManager object from the container.
CryptographyManager defaultCrypto 
    = EnterpriseLibraryContainer.Current.GetInstance<CryptographyManager>();

Diving in with an Example

You can download an example application (a simple console-based application) that demonstrates all of the scenarios you will see in the remainder of this chapter. You can run this directly from the bin\debug folder, or open the solution named Cryptography in Microsoft® Visual Studio® to see all of the code as you run the examples.

Ff953194.note(en-us,PandP.50).gifNote:
Before you attempt to run the example, you must create new encryption keys for the block to use to encrypt the data when using a symmetric encryption provider. This is because the key is tied to either the user or the machine, and so the key included in the sample files will not work on your machine. In the configuration console, select the AesManaged symmetric provider, and click the "..." button in the Key property to start the Key wizard. Use this wizard to generate a new key, save the key file, and automatically update the content of App.config. Then repeat this procedure for the RijndaelManager symmetric provider. Rijndael is an implementation of the AES algorithm. However, we will demonstrate both as we show you how to encrypt and decrypt both value types and objects.

Encrypting and Decrypting Data Using a Symmetric Provider

To encrypt and decrypt information, you use a symmetric encryption provider. As you saw earlier, the Cryptography block includes several symmetric encryption providers. The examples we provide use two of these: the AES managed symmetric algorithm provider and the Rijndael managed symmetric algorithm provider. The examples demonstrate how to use these providers to encrypt both a text string and an object (in our example this is a simple class named Product), and how to decrypt the encrypted item.

The Cryptography Manager exposes two methods for working with symmetric encryption providers:

  • The EncryptSymmetric method takes as parameters the name of a symmetric provider configured in the Cryptography block for the application, and the item to encrypt. There are two overloads of this method. One accepts a string and returns a base-64 encoded string containing the encrypted text. The second overload accepts the data to encrypt as a byte array, and returns a byte array containing the encrypted data.
  • The DecryptSymmetric method takes as parameters the name of a symmetric provider configured in the Cryptography block for the application, and the item to decrypt. There are two overloads of this method. One accepts a base-64 encoded string containing the encrypted text and returns the decrypted text. The second overload accepts a byte array containing the encrypted data and returns a byte array containing the decrypted item.

Encrypting and Decrypting a Text String

The first example, Encrypt and Decrypt a Text String using a Symmetric Algorithm, uses the AES managed symmetric algorithm provider to encrypt and decrypt a text string.

The code shown below creates a text string and then calls the EncryptSymmetric method of the Cryptography Manager, passing to it the name of the AES managed symmetric algorithm provider defined in the configuration of the application, and the text string to encrypt. To decrypt the resulting string, the code then calls the DecryptSymmetric method of the Cryptography Manager, passing to it (as before) the name of the AES managed symmetric algorithm provider defined in the configuration of the application, and the encrypted base-64 encoded string. We've removed some of the lines of code that simply write values to the console screen to make it easier to see the code that actually does the work.

// Define the text string instance to encrypt.
string sampleText = "This is some text to encrypt.";

// Use the AES Symmetric Algorithm Provider.
// The overload of the EncryptSymmetric method that takes a
// string returns the result as a Base-64 encoded string.
string encrypted = defaultCrypto.EncryptSymmetric("AesManaged", sampleText);

// Now decrypt the result string.
string decrypted = defaultCrypto.DecryptSymmetric("AesManaged", encrypted);

// Destroy any in-memory variables that hold sensitive information.
encrypted = null;
decrypted = null;

Notice that the last lines of the code destroy the in-memory values that hold the sensitive information used in the code. This is good practice as it prevents any leakage of this information should an error occur elsewhere in the application, and prevents any attacker from being able to dump the memory contents and view the information. If you store data in a string, set it to null, allowing the garbage collector to remove it from memory during its next run cycle. If you use an array, call the static Array.Clear method (passing in the array you used) to remove the contents after use.

Ff953194.note(en-us,PandP.50).gifNote:
You may also consider storing values in memory using the SecureString class, which is part of the Microsoft .NET Framework. However, in the current release of Enterprise Library, the methods of the Security block do not accept or return SecureString instances, and so you must translate them into strings when interacting with the block methods. For more information about using the SecureString class, see "SecureString Class" at http://msdn.microsoft.com/en-us/library/system.security.securestring.aspx.

When you run this example, you'll see the output shown below. You can see the value of the original string, the base-64 encoded encrypted data, and the result after decrypting this value.

Text to encrypt is 'This is some text to encrypt.'

Encrypted and Base-64 Encoded result is '+o3zulnEOeggpIqUeiHRD2ID4E85TSPxCjS/D6k
II4CUCjedFvlNOXjrqjna7ZWWbJp5yfyh/VrHw7oQPzUtUaxlXNdyiqSvDGcU814NNq4='

Decrypted string is 'This is some text to encrypt.'

Encrypting and Decrypting an Object Instance

The second example, Encrypt and Decrypt Data using a Symmetric Algorithm, uses the Rijndael managed symmetric algorithm provider to encrypt and decrypt an instance of the Product class defined within the example project.

The code shown below first creates a new instance of the Product class. We need to pass this to the EncryptSymmetric method of the Cryptography Manager, along with the name of the Rijndael managed symmetric algorithm provider defined in the configuration of the application, as an array of bytes. The easiest way to perform the conversion to a byte array is to take advantage of the SerializationUtility class in the Caching block. This class exposes two methods: ToBytes and ToObject. We use the ToBytes method to convert the Product instance into a byte array before passing it the EncryptSymmetric method.

Then the code decrypts the resulting byte array using the DecryptSymmetric method of the Cryptography Manager, passing to it (as before) the name of the Rijndael managed symmetric algorithm provider defined in the configuration of the application, and the encrypted byte array. The ToObject method of the SerializationUtility class then converts this back into an instance of the Product class. Again, we've removed some of the lines of code that simply write values to the console screen to make it easier to see the code that actually does the work.

// Create the object instance to encrypt.
Product sampleObject = new Product(42, "Fun Thing", 
                                   "Something to keep the grandchildren quiet.");

// Use the Rijndael Symmetric Algorithm Provider.
// Must serialize the object to a byte array first. One easy way is to use
// the methods of the SerializationUtility class from the Caching block.
byte[] serializedObject = SerializationUtility.ToBytes(sampleObject);

// The overload of the EncryptSymmetric method that takes a
// byte array returns the result as a byte array.
byte[] encrypted = defaultCrypto.EncryptSymmetric("RijndaelManaged",
                                                  serializedObject);

// Now decrypt the result byte array and de-serialize the 
// result to get the original object.
byte[] decrypted = defaultCrypto.DecryptSymmetric("RijndaelManaged", encrypted);
Product decryptedObject = (Product) SerializationUtility.ToObject(decrypted);

// Destroy any in-memory variables that hold sensitive information.
Array.Clear(encrypted, 0, encrypted.Length);
Array.Clear(decrypted, 0, decrypted.Length);
Array.Clear(serializedObject, 0, serializedObject.Length);
decryptedObject = null;

If you run this example, you'll see the output shown below. You can see the value of the properties of the Product class we created, the encrypted data (we base-64 encoded it for display), and the result after decrypting this data.

Object to encrypt is 'CryptographyExample.Product'
 - Product.ID = 42
 - Product.Name = Fun Thing
 - Product.Description = Something to keep the grandchildren quiet.

Encrypted result is 'System.Byte[]'
Contents (when Base-64 encoded for display) are:
OEnp9yOP6LInmsfFDaGfVR7RJbwU4/TQskYtIPsqXKcx4UhxMctzBPWXuUX8Q+RgKqYdGAZVVbSCR2Vx
yTmSDdYQNdiSohA5Fo6bWOqhOR5V0uxdcfNUgKhUhuIAhl5RZ8W5WD8M2CdMiqG1gPgQjJC2afwf1mJn
F/4ZB/oD9QcCyQf5d5F1Ww==

Decrypted object is 'CryptographyExample.Product'
 - Product.ID = 42
 - Product.Name = Fun Thing
 - Product.Description = Something to keep the grandchildren quiet.

Obtaining and Comparing Hash Values

To create and compare hash values, you use a hash provider. As you saw earlier, the Cryptography block includes several hash providers. The examples we provide use two of these: the SHA512 hash algorithm provider and the MD5Cng hash algorithm provider. The examples demonstrate how to use these providers to create a hash for both a text string and an object (in our example this is a simple class named Product), and how to compare the generated hashes with the original and other text strings and object instances.

The Cryptography Manager exposes two methods for working with hash providers:

  • The CreateHash method takes as parameters the name of a hash provider configured in the Cryptography block for the application, and the item for which it will create the hash value. There are two overloads of this method. One accepts a string and returns the hash as a string. The second overload accepts the data to encrypt as a byte array, and returns a byte array containing the hash value.
  • The CompareHash method takes as parameters the name of a hash provider configured in the Cryptography block for the application, the un-hashed item to compare the hash with, and the hash value to compare to the un-hashed item. There are two overloads of this method. One accepts the un-hashed item and the hash as strings. The second overload accepts the un-hashed item and the hash as byte arrays.

Creating and Comparing Hash Values for Text Strings

The example Create and Compare Hash Values for Text Strings uses the SHA512 hash algorithm provider to create a hash of three text strings. It then compares these hashes with the original and other values to demonstrate how even a minor difference between the original strings creates different hash values.

The code shown below creates three text strings that will be hashed. Notice that the second and third vary only in the letter case of two words. Then the code uses the CreateHash method of the Cryptography Manager to create the hashes of these three strings. In each case, the code passes to the CreateHash method the name of the SHA512 hash algorithm provider defined in the configuration of the application, and the text string.

Next, the code performs three comparisons of the hash values using the CompareHash method of the Cryptography Manager. It compares the hash of the first string with first string itself, to prove that they are equivalent. Then it compares the hash of the first string with the second string, to provide that they are not equivalent. Finally, it compares the hash of the second string with the third string, which varies only in letter case, to prove that these are also not equivalent.

As in earlier examples, we've removed some of the lines of code that simply write values to the console screen to make it easier to see the code that actually does the work.

// Define the text strings instance to encrypt.
string sample1Text = "This is some text to hash.";
string sample2Text = "This is some more text to hash.";
string sample3Text = "This is Some More text to hash.";

// Create the hash values using the SHA512 Hash Algorithm Provider.
// The overload of the CreateHash method that takes a
// string returns the result as a string.
string hashed1Text = defaultCrypto.CreateHash("SHA512CryptoServiceProvider",
                                               sample1Text);
string hashed2Text = defaultCrypto.CreateHash("SHA512CryptoServiceProvider",
                                               sample2Text);
string hashed3Text = defaultCrypto.CreateHash("SHA512CryptoServiceProvider",
                                                sample3Text);

// Compare the strings with some of the hashed values.
Console.WriteLine("Comparing the string '{0}' with the hash of this string:",
                   sample1Text);
Console.WriteLine("- result is {0}",
                  defaultCrypto.CompareHash("SHA512CryptoServiceProvider",
                                             sample1Text, hashed1Text));

Console.WriteLine("Comparing the string '{0}' with hash of the string  '{1}'",
                   sample1Text, sample2Text);
Console.WriteLine("- result is {0}", 
                  defaultCrypto.CompareHash("SHA512CryptoServiceProvider",
                                             sample2Text, hashed1Text));

Console.WriteLine("Comparing the string '{0}' with hash of the string  '{1}'",
                   sample2Text, sample3Text);
Console.WriteLine("- result is {0}",
                  defaultCrypto.CompareHash("SHA512CryptoServiceProvider",
                                             sample3Text, hashed2Text));

If you run this example, you'll see the output shown below. You can see the hash values of the three text strings, and the result of the three hash comparisons.

Text strings to hash and the resulting hash values are:

This is some text to hash.
v38snPJbuCtwfMUSNRjsgDqu4PB7ok7LQ2id4RJMZUGlhn+LTgX3FNEVuUbauokCpiCzzfZI2d9sNjlo
56NmuZ/8FY2sknxrD262TLSSYSQ=

This is some more text to hash.
braokQ/wraq9WVnKSqBROBUNG2lBwiICwX0lTGPSaooaJXL7/WcJvUCtBry8+0iRg+Rij5Xiz56jD4Zm
xcKrp7kGVDeWuA7jHeYiFZmGbOU=

This is Some More text to hash.
aw3anokiiBXPJfxZ5kf2SrlTEN3lokVlT+46t0V1B7der1wsNTD4dPxKQly8SDAjoCgCWwzSCh4k+OUf
O6/y6JIpFtWpQDqHO3JH+Rj25K0=

Comparing the string 'This is some text to hash.' with the hash of this string:
- result is True

Comparing the string 'This is some text to hash.' with hash of the string  'This
 is some more text to hash.'
- result is False

Comparing the string 'This is some more text to hash.' with hash of the string
'This is Some More text to hash.'
- result is False

Creating and Comparing Hash Values for Object Instances

The example Create and Compare Hash Values for Data Items uses the MD5Cng hash algorithm provider to create a hash of two instances of the Product class defined within the example project, demonstrating how different property values produce a different hash value. It then compares the second object instance with the hash of the first to show that they are different.

The code shown below starts by creating an instance of the Product class, and then serializes it using the ToBytes method of the SerializationUtility class. Then it calls the CreateHash method of the Cryptography Manager, passing to it the name of the MD5Cng hash algorithm provider defined in the configuration of the application, and the byte array generated from the Product class instance.

Next, the code repeats the process with another new instance of the Product class, with different values for its properties, and displays the hash of this to show that it is different from the other instance of the Product class created previously. Finally, the code compares the hash of the first instance of the Product class with the second instance of the same class to prove that they are not equivalent.

As in earlier examples, we've removed some of the lines of code that simply write values to the console screen to make it easier to see the code that actually does the work.

// Create the object instance to encrypt.
Product sample1Object = new Product(42, "Exciting Thing", 
                            "Something to keep you on your toes.");

// Create the hash values using the SHA512 Hash Algorithm Provider.
// Must serialize the object to a byte array first. One easy way is to use
// the methods of the SerializationUtility class from the Caching block.
byte[] serializedObject = SerializationUtility.ToBytes(sample1Object);

// The overload of the CreateHash method that takes a
// byte array returns the result as a byte array.
byte[] hashed1Object = defaultCrypto.CreateHash("MD5Cng", serializedObject);

// Do the same to generate a hash for another similar object with 
// different property values.
Product sample2Object = new Product(79, "Fun Thing", 
                            "Something to keep the grandchildren quiet.");
serializedObject = SerializationUtility.ToBytes(sample2Object);
byte[] hashed2Object = defaultCrypto.CreateHash("MD5Cng", serializedObject);

Console.WriteLine("Generated hash (when Base-64 encoded for display) is:");
Console.WriteLine(Convert.ToBase64String(hashed2Object));
Console.WriteLine();

// Compare the hashed values.
Console.WriteLine("Comparing second object with hash of the first object:");
Console.WriteLine("- result is {0}", 
                  defaultCrypto.CompareHash("MD5Cng",
                                            serializedObject, hashed1Object));

If you run this example, you'll see the output shown below. You can see the hash values of the two instances of the Product class, and the result of the hash comparison.

First object to hash is 'CryptographyExample.Product'
 - Product.ID = 42
 - Product.Name = Exciting Thing
 - Product.Description = Something to keep you on your toes.
Generated hash (when Base-64 encoded for display) is:
Gd2V77Zau/pgOcg1A2A5zk6RTd5zFFnHKXfhVx8LEi4=

Second object to hash is 'CryptographyExample.Product'
 - Product.ID = 79
 - Product.Name = Fun Thing
 - Product.Description = Something to keep the grandchildren quiet.
Generated hash (when Base-64 encoded for display) is:
1Eyal+AHf3e2QyEB+sqsGDOdux1Iom4z0zGLYlHlC78=

Comparing second object with hash of the first object:
- result is False

Creating Custom Cryptography Providers

While the Cryptography block contains providers for a range of hashing and encryption algorithms, you may find that you have specific requirements that none of these algorithms can satisfy. For example, you may wish to perform some company-specific encryption technique, or implement a non-standard hashing algorithm. You may even want to apply multiple levels of encryption based on business requirements or data handling standards relevant to your industry.

Ff953194.note(en-us,PandP.50).gifNote:
Be aware that you may introduce vulnerabilities into your application by using non-standard or custom encryption algorithms. The strength of any algorithm you use must be verified as being suitable for your requirements, and rechecked regularly to ensure that new decryption techniques or known vulnerabilities do not compromise your application.

You can implement a custom hashing provider or a custom encryption provider, and integrate them with Enterprise Library. The Cryptography block contains two interfaces, IHashProvider and ISymmetricCryptoProvider, that define hashing and encryption provider requirements. For a custom hashing provider, you must implement the CreateHash and CompareHash methods based on the hashing algorithm you choose. For a custom encryption provider, you must implement the Encrypt and Decrypt methods based on the encryption algorithm you choose.

One other way that you may want to modify the block is to change the way that it creates and stores keys. By default, it stores keys that you provide or generate for the providers in DPAPI-encrypted disk files. You can modify the KeyManager class in the block to change this behavior, and modify the Wizard that helps you to specify the key in the configuration tools.

For more information about extending and modifying the Cryptography block, see the online documentation and the help files installed with Enterprise Library.

Summary

This chapter looked at the Cryptography Application Block. It began by discussing cryptographic techniques and strategies for which the block is suitable, and helped you decide how you might use the block in your applications. The two most common scenarios are symmetric encryption/decryption of data, and creating hash values from data. Symmetric encryption is useful whenever you need to protect data that you are storing or sending across a network. Hashing is useful for tasks such as storing passwords so that you can confirm user identity without allowing the passwords to be visible to anyone who may access the database or intercept the passwords as they pass over a network.

Many types of cryptographic algorithms that you may use with the Cryptography block require access to a key for both encryption and decryption. It is vitally important that you protect this key both to prevent unauthorized access to the data and to allow you to encrypt it when required. The Cryptography block protects key files using DPAPI encryption.

The bulk of the chapter then explored the main techniques for using the block. This includes encrypting and decrypting data, creating a hash value, and comparing hash values (for example, when verifying a submitted user password). As you have seen, the block makes these commonly repeated tasks much simpler, while allowing the configuration to be easily managed post-deployment and at run time by administrators and operations staff.


Show: