The RSA algorithm can be used for both privacy and digital signing. In Chapter 4, we saw how RSA can be used for keeping secrets, and especially for sharing secret symmetric keys. In this chapter, we look at RSA digital signatures, which is the flip side of the coin. Whereas privacy is achieved by encrypting with the public key and decrypting with the associated private key, digital signing is achieved the other way around, by encrypting with the private key and decrypting with the matching public key. For digital signatures, it turns out that it is not actually necessary to encrypt the entire original message. It is entirely sufficient, as well as much more efficient, to generate a hash of the original message, and then just encrypt that smaller hash value with the private key. Anyone with the matching public key (i.e., everybody) can then decrypt that hash with the public key for verification purposes. If the decrypted hash matches the recalculated hash of the actual message received, then the receiver can be quite confident that the original message that generated the hash must also match the received message. This comes from the fact that it is extremely difficult to find any two inputs that produce the same hash output. An RSA Signature Example ProgramThe RSASignature example program demonstrates how to create and verify an RSA digital signature for a message. Figure 5-4 shows the RSASignature example program generating and verifying a digital signature. If you create the digital signature for the message by clicking the Create Signature button, and then, without modifying the original message, you test the signature by clicking the Verify Signature button, you will see a dialog box display the fact that the verification succeeded. If you click the Create Signature button, but then modify the message in the TextBox control before clicking the Verify Signature button, the dialog box indicates that verification fails. Thus, the program detects that the message has been tampered with. Figure 5-4. The RSASignature example program.
This example is somewhat contrived, since the digital signing and signature verification are all done within a single program window. This is done this way in the example purely for convenience, so that the overall effect of working with digital signatures can be demonstrated in a compact manner. A real-world example involving digital signatures would more likely be a client/server or distributed application scenario, such as an email client or Internet-based banking. The buttonSign_Click method that performs the digital signing on the message data is shown next . User interface code is ignored here so that we can focus on the cryptographic aspects of the program. 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 RSA object using default key RSACryptoServiceProvider rsa = new RSACryptoServiceProvider (); //sign hash using OID for SHA-1 signaturebytes = rsa. SignHash (hashbytes, "1.3.14.3.2.26"); //provide RSA parameters to verification rsaparams = rsa. ExportParameters (false); //display digital signature in hex format ... //display RSA parameter details in hex format ... //do UI stuff ... } The previous code listing shows a message hash being generated, which is then digitally signed by calling the SignHash method of the RSA object. The ExportParameters method is then used to store only the public key information in an RSAParameters object to be used later for verification. The verifier needs to know only the public key information, not the private key information, and only the signer needs to know the entire key, including both public and private parts . [12] This is why the signer creates the RSACryptoServiceProvider object, and then exports only the public key information by calling the ExportParameters method with a false parameter.
Now let's look at the buttonVerify_Click method that verifies the digital signature on the message. The hash is recalculated on the message, since it might have been tampered with, which is exactly what we are attempting to detect. Then a new RSA object is created, but, this time, the automatically generated public key information is replaced by calling ImportParameters on the same RSAParameters object established earlier in the signing method. This ensures that the RSA parameters that were used in the signing of the message are identical to those to be used now in the verification of the signature. Although the user interface code is not shown here, the program then displays the result of the call to VerifyHash in a message box. 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 RSA object using parameters from signing RSACryptoServiceProvider rsa = new RSACryptoServiceProvider (); rsa. ImportParameters (rsaparams); //do verification on hash using OID for SHA-1 bool match = rsa. VerifyHash ( hashbytes, "1.3.14.3.2.26", signaturebytes); //show message box with result of verification ... //do UI stuff ... } In order to communicate the necessary information from the signing method to the verification method, we provide two fields. The first one is an RSAParameters object mentioned earlier. This object encapsulates public key parameter information for the algorithm, such as the RSA key pair information. The second is a byte array that will contain the digital signature when it is generated from the message in the signing method. Although the actual text message does need to be communicated between the signing code and the verifying code, it is not stored as a field in this program. Instead, the message is stored and retrieved directly from a textbox in the user interface, allowing the user to modify it. This allows the user to see the effect of tampering with the message between the operations of signing and verification. This helps in visualizing how it works and allows you to interact with it by tampering with the signed data, but in a realistic scenario, it would probably be transmitted between distinct applications. //variables communicated from signing to verifying RSAParameters rsaparams; byte[] signaturebytes; |