Poor Application Performance Is Caused By Flaws in Design Implementation
Sometimes, even with a properly-normalized database, conditions are such that you will still encounter performance problems. One such case was a company that was having a terrible time trying to increase productivity without increasing headcount.
One key to increasing productivity per worker is to document and then automate processes.
You can do process analysis; you can identify those manual processes that can be automated.
However, if you’re working with an inflexible legacy system, one for which there is no source code, and if you’re trying to integrate new automated processes into such a system, you may be running up against a brick wall. In the case that I'm describing, which represents a legacy system that had been created years before, there was no source code or documentation. Any previous attempts to modify the schema had caused the custom application that was core to the business to fail.
Their immediate need was the invoicing process. There was so much data stored in the invoicing subsystem of the database that it took 36 hours to run the invoicing routine which ran every ten days. How do you shorten the amount of time that it takes to run invoicing when you can’t touch either the database schema or the invoicing application?
The answer lay in the data content. This database schema was fairly well designed. While there were a few places in the schema that might have benefited from some design tweaking, in general the schema was solid. The flaw in this design was its implementation; there was no built-in method to rid the database of old data, and the weight of old data was slowing down processing. No amount of indexing seemed to help. There was just too much old data stored in the database.
Even the best-designed database will stagger under the load of too much data if the queries that call the data are not properly constructed or don’t use index structures wisely. In this case, the invoicing application was reading through the entire set of invoicing data before selecting those accounts that required further processing. As a result, every time invoicing was run, many millions of unneeded records were being read. Any attempt to change the invoicing system was met with defeat — the company that crafted the custom application had left no source code behind, and had hard-wired application access to the database.
In situations like this, when you cannot modify legacy code or even the legacy schema, you need to approach the solution from a very low level. Use a technique like horizontal data partitioning to physically separate current data from aged data. Your biggest challenges will be to determine what constitutes “aged” data, and then to develop algorithms that successfully identify the aged data, so that you can move it into its own table or onto its own archive database. For this task you’ll need the input of the business users in the organization. They understand how to identify "aged" data, and what constitutes a current data set.
Once you have separated the aged data from the current data, you'll want to create a set of scheduled jobs, using these partitioning algorithms, so that periodically, as data becomes aged, you can move it to the aged data set. This will keep the current invoice data set lean and mean, with the end result that the invoicing routine will run swiftly. In this case, the time required to run the invoicing routine was reduced to just 3 hours from 36 hours.
Designing for Simplified Cryptography Functionality
Cryptography in applications can be implemented in many ways. Typically, developers must duplicate code to perform common tasks. To meet the needs of their organization, they may have to familiarize themselves with many different ways of implementing cryptography. The Cryptography Application Block is designed to simplify and abstract the implementation of cryptography in applications.
Design Implications
Ensuring that the application block simplifies the task of accessing cryptography functionality resulted in the following design decisions:
It should expose only a small number of methods that a developer would need to understand.
It should accept and return data using consistent data types.
It should support common algorithms.
The following subtopics describe these decisions.
Small Number of Methods
The application block supports a small number of methods that simplify the most common cryptography tasks. It provides a Cryptographer class and the corresponding non-static CryptographyManager façade (for use with the Unity Application Block) that define the set of static methods the application block supports. These methods include the following:
CreateHash
CompareHash
EncryptSymmetric
DecryptSymmetric
Consistent Data Types
Each public method has two overloads. One overload accepts parameters as type string; the other overload accepts the parameters as a byte array. For example, the following code shows the two overloads for the CreateHash method
C# Copy Code
public static byte[] CreateHash(string hashInstance, byte[] plainText)
public static string CreateHash(string hashInstance, string plaintext)
Visual Basic Copy Code
Public Shared Function CreateHash(ByVal hashInstance As String, ByVal plainText As Byte()) As Byte()
Public Shared Function CreateHash(ByVal hashInstance As String, ByVal plainText As String) As String
Common Algorithms
The Cryptography Application Block includes two implementations of symmetric providers. The DpapiSymmetricCryptoProvider uses DPAPI to provide cryptography services. Developers can use the SymmetricAlgorithmProvider to select and configure symmetric algorithms included with the .NET Framework.
The Cryptography Application Block includes two implementations of hash providers. The KeyedHashAlgorithmProvider allows developers to configure hash algorithms included with the .NET Framework that require a generated key. The HashAlgorithmProvider allows developers to configure hash algorithms that do not require a generated key. Both providers allow the developer to ensure that a random string (known as a salt value) is generated and pre-pended to the plaintext before hashing. Consider using salt values for storing passwords, because they dramatically slow dictionary attacks as each entry in the dictionary must be hashed with each salt value.
Note:
SHA256Managed is the recommended hash algorithm; the SHA1Managed algorithm is still acceptable but not encouraged. The MD4 and MD5 algorithms are not recommended. For symmetric encryption, AES (such as Rijndael) is currently recommended; DES is no longer recommended.
Design of the Cryptography Application Block of Enterprise Library
The Cryptography Application Block includes support for the following features:
- Encryption algorithms
- Hashing algorithms
- Multiple cryptography providers
- Additional implementations of cryptography providers
- Key protection with DPAPI
Design Goals
The Cryptography Application Block was designed to achieve the following goals:
Provide a simple and intuitive interface to the commonly required functionality.
Encapsulate the logic that is used to perform the most common application cryptography tasks.
Present a standard consistent model for common cryptography tasks, using common names for algorithms.
Make sure the application block is extensible.
Exert minimal or negligible performance impact compared to manually written cryptography code that accomplishes the same functionality.
Provide a key management model that can be customized to satisfy your organization's security requirements.
Design Highlights
Figure 1 illustrates the design of the Cryptography Application Block.
Figure 1
Design of the Cryptography Application Block
The Cryptography Application Block separates decisions about how cryptographic functions are implemented from how an application uses them. The application block is designed so you change the behavior of a cryptography provider without changing the application code.
The Cryptographer class is a façade that mediates between the client code and the Cryptography Application Block's cryptographic functions. The client code calls static methods on the Cryptographer class to create hashes, compare hashes, encrypt data, and decrypt data. Unless you are using the Unity Integration approach, each static method instantiates a factory class and passes the configuration source to the factory class's constructor. The factory uses the configuration data to determine the type of the provider to create.
Note:
If you use the Unity Integration approach to create instances of objects from the Cryptography Application Block, you must use the non-static façade named CryptographyManager. This class exposes the same API as the Cryptographer class static façade. For more information about using the Unity Application Block to create and inject instances of Enterprise Library objects, see Creating Objects Using the Unity Application Block.
The DpapiCryptographer class uses DPAPI to encrypt and decrypt data. DPAPI uses logon credentials to encrypt data. The logon credentials can either be a user's logon credentials or the local computer's logon credentials. If you use the local computer's logon credentials, DPAPI allows all applications that run under those credentials to decrypt that data. To counteract this, you can use an additional secret to protect the data. This additional secret is named entropy. The DpapiCryptographer class has overloads of the Encrypt and Decrypt methods that accept an entropy value.
Note:
Developers should be careful about how they store the entropy value. If it is simply saved to an unprotected file, attackers can access the file, retrieve the entropy value, and use it to decrypt an application's data.
The SymmetricCryptographer class encapsulates provider implementations that derive from the abstract base class SymmetricAlgorithm, which is located in the .NET Framework's System.Security.Cryptography namespace. This means that you can use the SymmetricCryptographer class with any of the .NET Framework symmetric algorithms, such as the Rijndael symmetric encryption algorithm. The application block uses DPAPI to encrypt and decrypt the symmetric algorithm key.
Key Management Model
You use the configuration tools to select a cryptographic provider algorithm. If the algorithm requires a key, the configuration tools prompt you to select an existing key or to create a new key. When you create a new key, the configuration tools use the Cryptography Application Block to encrypt the key, and then store the encrypted key in its own text file. The application block uses DPAPI to encrypt the keys. When your application executes, the application block uses DPAPI to decrypt the key, and then it uses the key to encrypt or decrypt your data.
The Cryptography Application Block's design-time component includes the Cryptographic Key Wizard. You can use this wizard to either create a new key or to use an existing key. You use an existing key by selecting a file that contains a key encrypted with DPAPI. Typically, this is a key that you previously created with the configuration tools.
You can also use the configuration tools to export an existing key to a file. When you export a key, the configuration tools prompt you to supply a password to use to encrypt the key. The application block KeyManager class calls the KeyReaderWriter class to encrypt the key and create the file. The file contains a version number, salt value, and the encrypted key.
Finally, you can use the Cryptographic Key Wizard to import a previously-exported key. This means that if you must distribute the key to multiple computers, you can use the configuration tools to export your keys to an encrypted text file, transport the key file to the computers that require the key, and then use the configuration tools again to import the encrypted text file. When you import the encrypted key file, the configuration tools will prompt you for the password that you used to encrypt the file.
Posted in: .NET Framework| Tags: Enterprise Library Cryptography Application Block Design