14.8 Send a Secret Securely Using Asymmetric Encryption


Problem

You need to use asymmetric encryption to send a secret.

Solution

Instantiate the asymmetric algorithm class System.Security.Cryptography.RSACryptoServiceProvider . Use the RSACryptoServiceProvider.Encrypt method and the intended recipient's public key to encrypt the message. Later the recipient will use the RSACryptoServiceProvider.Decrypt method and the private key to decrypt the encrypted secret.

Discussion

The .NET Framework defines a class hierarchy for asymmetric algorithms similar to that defined for symmetric algorithms (discussed in recipe 14.6). All asymmetric algorithms must extend a common abstract base class named System.Security.Cryptography.AsymmetricAlgorithm . There are two concrete asymmetric algorithm implementations :

  • System.Security.Cryptography.RSACryptoServiceProvider

  • System.Security.Cryptography.DSACryptoServiceProvider

As the class name suffix CryptoServiceProvider implies, both classes wrap functionality provided by the native Win32 CryptoAPI. However, only the RSACryptoServiceProvider class supports data encryption. The DSACryptoServiceProvider class implements the Digital Signature Algorithm (DSA), which you can use only to create digital signatures. (See the Federal Information Processing Standard [FIPS] 186-2 available at http://www.itl.nist.gov/fipspubs/ for details of the DSA.)

Although you can instantiate an asymmetric algorithm object using the static factory method Create of the AsymmetricAlgorithm base class, there is little value in doing so. The AsymmetricAlgorithm class does not declare the methods used by the RSACryptoServiceProvider class to encrypt and decrypt data. Instead, you should instantiate the RSACryptoServiceProvider class directly using one of its constructors.

Before you can encrypt or decrypt data with an RSACryptoServiceProvider object, you need access to the appropriate keys. Asymmetric algorithm keys are very different from those of symmetric algorithms. First, there are two components : a public key and a private key. Together these keys are referred to as a key pair . Second, instead of simply being a series of randomly generated bytes, asymmetric keys are created according to a special formula. There is a special mathematical relationship between the public and private keys; this special relationship enables the asymmetric algorithm to encrypt data with one key and decrypt the data only with the other key. Each asymmetric algorithm uses its own key generation formula, and the concrete implementation classes encapsulate the functionality necessary to generate new keys correctly.

As the name suggests, the public key isn't secret and the owner can freely send it to you via an e-mail message, or even post it up on a Web site or key distribution server for the world to see. People wanting to send secrets use the public key to encrypt the secret. The recipient then uses the private key to decrypt the secret. The private key must remain secret; anybody who possesses the private key can decrypt data encrypted using the public key counterpart .

To create an asymmetrically encrypted secret, you must have the intended recipient's public key and load it into an RSACryptoServiceProvider object. There are two ways to load the public key:

  • Use the RSACryptoServiceProvider.ImportParameters method to import a System.Security.Cryptography.RSAParameters structure, which contains the recipient's public key information. The key owner would normally generate the RSAParameters structure using the RSACryptoServiceProvider.ExportParameters method and send it to you. However, they might send you the public key byte values, which you must load manually into an RSAParameters structure.

  • Use the RSACryptoServiceProvider.FromXmlString method to load the public key data from an XML string encoding of the public key. The owner would normally generate the XML key data using the RSACryptoServiceProvider.ToXmlString method and send it to you.

    Note  

    ImportantBoth the ExportParameters and ToXmlString methods of the RSACryptoServiceProvider class take a single Boolean argument, which if true , causes an RSACryptoServiceProvider object to export both its public and private keys. It's important that you specify false when exporting keys for distribution or storage.

Once you have loaded the recipient's public key into the RSACryptoServiceProvider object, you are ready to encrypt the data. Asymmetric algorithms are much slower than symmetric algorithms when encrypting and decrypting data. Because of this, you will rarely use an asymmetric algorithm to encrypt large quantities of data. Usually, if encrypting large amounts of data, you will use a symmetric algorithm and then encrypt the symmetric keys using an asymmetric algorithm so that you can safely send the symmetric keys with the data. Recipe 14.10 contains a complete discussion of just such a scenario. In keeping with this usage pattern, the RSACryptoServiceProvider class does not support a System.IO.Stream -based encryption and decryption model, which was used in recipe 14.6.

To encrypt data with an RSACryptoServiceProvider object, call the Encrypt method, passing it a byte array containing the plaintext you want to encrypt; Encrypt will return a byte array containing the ciphertext . The Encrypt method also takes a second Boolean argument that specifies the type of padding the RSACryptoServiceProvider object should use. Padding specifies how the asymmetric algorithm object should process the plaintext data before encryption. Padding both ensures that the asymmetric algorithm does not need to process partial blocks of data, and protects ciphertext against certain forms of cryptographic attack. A description of the available padding schemes is beyond the scope of this book. Generally, if you are running Microsoft Windows XP or a later operating system, you should specify true for the padding argument; otherwise , you must specify false or Encrypt will throw the exception System.Security.Cryptography.CryptographicException .

Decryption of the message is as simple as encryption. The recipient creates an RSACryptoServiceProvider object and loads it with their private key. Usually, this key will be stored in a CryptoAPI managed key container (discussed further in recipe 14.9). The recipient calls RSACryptoServiceProvider.Decrypt and passes in the ciphertext you sent them. Again, they must specify the padding mechanism to use, and it must be the same as that used to encrypt the data. The Decrypt method returns a byte array containing the decrypted plaintext. If this represents a string, the recipient must convert the byte array to its appropriate string value using the System.Text.Encoding class.

Note  

The RSACryptoServiceProvider class inherits the methods named EncryptValue and DecryptValue from its parent class System.Security.Cryptography.RSA . The RSACryptoServiceProvider class does not implement these methods and throws the exception System.NotSupportedException if you call them.

The example AsymmetricEncryptionExample class listed here demonstrates the use of the RSACryptoServiceProvider class to encrypt a string and then decrypt it. The example's Main method (not shown here but available in the accompanying sample code) takes the message to encrypt as a command- line argument. The Main method generates a key pair and stores them to a CryptoAPI managed key container named MyKeys; the public key is exported to an RSAParameters object. This is purely to facilitate the demonstration ”in the real world, the sender would have only the recipient's public key, while the recipient kept the private key secret.

The Main method then calls the example's EncryptMessage method passing a byte representation of the message string and the RSAParameters object containing the recipient's public key. The EncryptMessage method returns a byte array containing the ciphertext version of the message, which you would send to the intended recipient. Next the Main method calls the example's DecryptMessage method, passing the message ciphertext and a CspParameters object that contains a reference to the MyKeys key container, which contains the recipient's private key. During the process, the Main method displays the original message, the ciphertext, and finally the decrypted message.

 using System; using System.Text; using System.Security.Cryptography; public class AsymmetricEncryptionExample {     // Main method not shown, see sample code          // A method to RSA encrypt a message using the PUBLIC KEY     // contained in an RSAParameters structure.      private static byte[] EncryptMessage(byte[] plaintext,          RSAParameters rsaParams) {                  byte[] ciphertext = null;                  // create an instance of the RSA algorithm.         using (RSACryptoServiceProvider rsaAlg =              new RSACryptoServiceProvider()) {                      rsaAlg.ImportParameters(rsaParams);             // encrypt the plaintext using OAEP padding, which             // is only supported on Windows XP and later versions             // of Windows.             ciphertext = rsaAlg.Encrypt(plaintext, true);         }                  // Clear the values held in the plaintext byte array. This ensures          // that the secret data does not sit in memory after you release          // your reference to it.          Array.Clear(plaintext, 0, plaintext.Length);                  return ciphertext;     }     // A method to decrypt an RSA encrypted message using the PRIVATE KEY     // from the key container specified by the CspParameters object.     private static byte[] DecryptMessage(byte[] ciphertext,          CspParameters cspParams) {         // Declare a byte array to hold the decrypted plaintext.         byte[] plaintext = null;                  // create an instance of the RSA algorithm.         using (RSACryptoServiceProvider rsaAlg =              new RSACryptoServiceProvider(cspParams)) {             // decrypt the plaintext using OAEP padding.             plaintext = rsaAlg.Decrypt(ciphertext, true);         }                  return plaintext;     } } 

Running the command, AsymmetricEncryptionExample "Meet me under the clock tower at noon." produces output similar to that shown here.

 Original message = Meet me under the clock tower at noon. Formatted Ciphertext = 78-16-4C-17-20-1C-F6-94-95-4A-FE-BE-2A-CF-6A-8B-2C- D2-16-E6-BB-55-F0-DE-E1-93-F6-31-A4-05-AA-33-29-33-D9-6D-43-D2-1E-D0-10-45- AF-34-7C-B6-FB-18-ED-D1-CF-B2-30-4E-43-85-3C-65-A5-57-B3-A2-2E-19-95-2A-0F- 11-98-71-F7-1B-57-B3-BB-5E-E3-05-A8-61-A7-FA-99-C6-4A-B5-E2-90-B1-B6-70-64- 6F-EA-45-69-4D-2B-16-27-DC-6A-2E-26-E1-9D-F7-B8-93-2A-87-3D-3C-7F-7A-DF-C5- A0-7E-B9-9F-41-6D-95-A0-21-93-11 Decrypted message = Meet me under the clock tower at noon. 
Note  

Notice that if you run the example multiple times using the same message and keys as input, the ciphertext is different. Although initially confusing, this is expected behavior. The padding mechanism used by the RSACryptoServiceProvider class introduces random data to thwart certain types of cryptographic attack.




C# Programmer[ap]s Cookbook
C# Programmer[ap]s Cookbook
ISBN: 735619301
EAN: N/A
Year: 2006
Pages: 266

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net