.NET Security and Cryptography
The asymmetric algorithm class inheritance hierarchy, which is located in the System.Security.Cryptography namespace, is shown in Figure 5-5. Not shown in this figure is that AsymmetricAlgorithm derives from the Object class. Recall from Chapter 4 that the AsymmetricAlgorithm class is abstract and derives into the DSA and RSA classes, which are also abstract. The RSA and DSA classes further derive into the RSACryptoServiceProvider and DSACryptoServiceProvider classes, which provide concrete implementations of the RSA and DSA algorithms. These are both based on the underlying CryptoAPI support provided by the Windows operating system. Other implementations of RSA and DSA may be implemented by either yourself or other vendors ; however, in most cases the implementation provided by .NET is recommended. Figure 5-5. The asymmetric algorithm hierarchy.
Now let's consider the public methods and properties of the DSACryptoServiceProvider class. As is the case with all of the symmetric and asymmetric algorithms, this class's constructor automatically generates its own key information at creation time. The DSACryptoServiceProvider Class
The public properties of the DSACryptoServiceProvider class are the following:
DSACryptoServiceProvider also has several public methods that you may be interested in using. There is some overlap in the provided functionality, which means that you can often accomplish the same effect in multiple ways. The most important public methods of the DSACryptoServiceProvider class are the following:
A DSA Programming Example
The DSAAlgorithm example program demonstrates how to create and verify a DSA digital signature. You should see many similarities between this example and the RSASignature example we looked at earlier in this chapter. After all, even though DSA and RSA are implemented using different algorithms, they are both used for the same purpose when it comes to digital signing. Figure 5-6 shows the DSAAlgorithm example program generating and verifying a digital signature for a message. As you can see, this example's user interface works in exactly the same way as the previous RSASignature example program. You enter a message, create a digital signature, and, after either modifying or not modifying the original message, you verify the signature. A dialog box will display whether or not the message has been tampered with. Figure 5-6. The DSAAlgorithm example program.
The buttonSign_Click method, which performs the digital signing on the message data, is shown next . Again, user interface code is ignored here so that we can focus on the cryptography. This DSA code example performs the same basic logic seen in the previous RSA digital signature example. private void buttonSign_Click ( object sender, System.EventArgs e) { //get original message as byte array byte[] messagebytes = Encoding.UTF8.GetBytes( textOriginalMessage.Text); //create digest of original message using SHA1 SHA1 sha1 = new SHA1CryptoServiceProvider (); byte[] hashbytes = sha1. ComputeHash (messagebytes); //display hash bytes in hex format ... //create DSA object using default key DSACryptoServiceProvider dsa = new DSACryptoServiceProvider (); //sign hash using OID for SHA-1 signaturebytes = dsa. SignHash (hashbytes, "1.3.14.3.2.26"); //provide DSA parameters to verification dsaparams = dsa. ExportParameters (false); //display digital signature in hex format ... //do UI stuff ... } The buttonVerify_Click method performs the digital signature verification on the message. Again, this is very similar to the logic shown in the RSA programming example shown earlier. Once the hash has been performed on the received message, the VerifyHash method is used to verify that this hash is valid. private void buttonVerify_Click( object sender, System.EventArgs e) { //get possibly modified message as byte array byte[] messagebytes = Encoding.UTF8.GetBytes( textOriginalMessage.Text); //create digest of original message using SHA1 SHA1 sha1 = new SHA1CryptoServiceProvider (); byte[] hashbytes = sha1. ComputeHash (messagebytes); //create DSA object using parameters from signing DSACryptoServiceProvider dsa = new DSACryptoServiceProvider (); dsa. ImportParameters (dsaparams); //do verification on hash using OID for SHA-1 bool match = dsa. VerifyHash ( hashbytes, "1.3.14.3.2.26", signaturebytes); //show message box with result of verification ... //do UI stuff ... } //variables communicated from signing to verifying DSAParameters dsaparams; byte[] signaturebytes; We have just seen in the DSAAlgorithm and RSASignature examples that working with digital signatures via the DSACryptoServiceProvider and RSACryptoServiceProvider classes is virtually identical. Such consistency is what you would expect from a well-designed class library such as .NET. You simply call the SignHash method to sign the message hash, and then you call the VerifyHash method to check the signature for validity, in exactly the same manner, regardless of whether you are using RSA or DSA. If the message has been tampered with since it was signed, the VerifyHash method detects the problem. In addition, if the private key, which was automatically generated by the call to SignHash , does not match with the public key, used in the call to VerifyHash , then again, VerifyHash method detects the problem. In this way, the digital signature ensures that the message is coming from the authentic private key owner. When you look at the code in these two examples, you may notice that there is nothing that explicitly generates the key pair or transmits the public key. Actually, the key pair is automatically produced when the DSACryptoServiceProvider or RSACryptoServiceProvider class is instantiated . The public key is then transmitted from the sender to the receiver via the calls to the ExportParameters and ImportParameters methods of the DSACryptoServiceProvider or RSACryptoServiceProvider classes. These two example programs show only one of several techniques for accomplishing the same basic result. For example, rather than explicitly creating a hash byte array and then calling SignHash and VerifyHash , you could accomplish the same effect by simply calling SignData , which automatically generates a new hash, followed by a call to VerifyData. SignData and VerifyData do not require a preexisting hash, and they do not require an OID, but rather take a simple string name, such as " SHA1 " or " MD5 " to indicate the hash algorithm to be used. Yet another approach is available in the case of DSA by calling the CreateSignature method, which creates a digital signature byte array directly from a hash byte array. Then a subsequent call to the VerifySignature method, passing in the original hash byte array along with the signature byte array, returns a boolean result indicating success or failure. There are two small differences between RSA and DSA to note here. Unlike the DSACryptoServiceProvider class, the RSACryptoServiceProvider class does not support the CreateSignature and VerifySignature methods. The second difference results from the fact that the DSA algorithm does not support true encryption/decryption and therefore can be used only for signatures, not for privacy. Therefore, DSACryptoServiceProvider does not support the Decrypt and Encrypt methods, which are supported by RSACryptoServiceProvider . Other than these small differences, the two classes have identical public methods and fields. |