[ Team LiB ] |
15.2 Programming Asymmetrical EncryptionThe .NET Framework takes the same approach to representing asymmetric algorithms as it does for symmetric algorithms and hashing algorithms; abstract classes extend the System.Security.Cryptography.AsymmetricAlgorithm class for each of the supported algorithms. Individual implementations of the algorithms extend the abstract class, supporting the possibility of more than one implementation of an algorithm. Figure 15-6 shows the class hierarchy that supports asymmetric encryption algorithms, which is very simple because the .NET Framework supports only the RSA algorithm. Figure 15-6. The .NET Framework class hierarchy for asymmetric encryption algorithms15.2.1 The AsymmetricAlgorithm classDifferent asymmetric algorithms can take very different approaches to encrypting data, and the abstract AsymmetricAlgorithm class provides very little in the way of common functionality. Table 15-2 lists the pubic methods of the AsymmetricAlgorithm class.
15.2.2 The RSA classThe RSA class is the abstract representation of the RSA algorithm and extends AsymmetricAlgorithm. This class provides the common functionality shared by any implementation of the underlying algorithm and allows the algorithm to be employed without regard to the implementation details; however, as you will see in the following sections, the RSA class is not as useful as it should be. Table 15-3 summarizes the public members of the RSA class.
The EncryptValue and DecryptValue methods are not as useful as they seem, as we will explain in the next section. The value of the RSA class is the addition of the ImportParameters and ExportParameters methods, which allow the public or private keys to be imported into or exported from an instance of the class. Table 15-4 details the members of the RSAParameters structure, which represents RSA keys as a related series of byte arrays.
You will be familiar with the purpose of the RSAParameters values Modulus, Exponent, and D from Section 15.1.1 in this chapter. The other fields represented by the structure can be used to increase the performance of the decryption function. The performance enhancement is not part of the RSA algorithm specification, but the RSA class only imports private keys using RSAParameters structures that contain all of the addition values. You do not need to understand how the performance enhancements work, but you should be aware that the .NET RSA classes always expect these additional values. 15.2.3 The RSACryptoServiceProvider ClassThis class is the only asymmetric encryption implementation class contained in the .NET Framework. Unfortunately, while this class extends the abstract RSA class, it does not implement the EncryptValue and DecryptValue methods, meaning that you must work with the implementation class directly to use the RSA algorithm. Table 15-5 details the new methods introduced by the RSACryptoServiceProvider class.
15.2.4 Instantiating the AlgorithmThe RSACryptoServiceProvider class does not implement all of the methods defined by the abstract RSA class. There is no purpose in using the Create method specified in the AsymmetricAlgorithm class; the abstraction advantages offered with symmetric and hashing algorithms do not apply to RSA encryption, because you must always create instances of the implementation class to be able to use the Encrypt and Decrypt methods: # C# RSACryptoServiceProvider x_alg = new RSACryptoServiceProvider( ); # Visual Basic .NET Dim x_al2g As RSACryptoServiceProvider = New RSACryptoServiceProvider( ) 15.2.5 Using RSA KeysEven though you cannot use the abstract classes to encrypt and decrypt data, the methods that they define do allow you to configure the keys used by instances of the RSACryptoServiceProvider class. The AsymmetricAlgorithm class provides the LegalKeySizes property, which returns an array of the KeySizes structure, specifying all of the key lengths that the algorithm supports. This is the same model used by the SymmetricAlgorithm class (see Section 14.3.3.1 of Chapter 14 for full details). The .NET RSA implementation supports key lengths from 384 to 16384 bits, in 8-bit steps, and the size of key you wish to use is set using the KeySize property. The RSA implementation will create a new key pair automatically if you have not imported a key value before you encrypt or decrypt data. You can export the details of this key using the ExportParameters method, which returns an instance of the RSAParameters structure. This method accepts a Boolean argument. If the argument is true, then the private key is exported; otherwise, only the details of the public key are included: # C# RSACryptoServiceProvider x_alg = new RSACryptoServiceProvider( ); // export only the public key RSAParameters x_public_params = x_alg.ExportParameters(false); // export the private key RSAParameters x_private_params = x_alg.ExportParameters(true); # Visual Basic .NET Dim x_alg As RSACryptoServiceProvider = New RSACryptoServiceProvider( ) ' export only the public key Dim x_public_params As RSAParameters = x_alg.ExportParameters(False) ' export the private key Dim x_private_params As RSAParameters = x_alg.ExportParameters(True) The most common use for the ExportParameters method is to export details of a key from one instance of an algorithm and then import them to another using the ImportParameters method: # C# // create an instance of the RSA algorithm RSACryptoServiceProvider x_alg = new RSACryptoServiceProvider( ); // export only the public key RSAParameters x_public_params = x_alg.ExportParameters(false); // create a second instance of the algorithm RSACryptoServiceProvider x_second_algorithm = new RSACryptoServiceProvider( ); // import the public key x_second_algorithm.ImportParameters(x_public_params); # Visual Basic .NET ' create an instance of the RSA algorithm Dim x_alg As RSACryptoServiceProvider = New RSACryptoServiceProvider( ) ' export only the public key Dim x_public_params As RSAParameters = x_alg.ExportParameters(False) ' create a second instance of the algorithm Dim x_second_algorithm As RSACryptoServiceProvider = New RSACryptoServiceProvider( ) ' import the public key x_second_algorithm.ImportParameters(x_public_params) The RSAParameters structure is also useful if you need to export a key into a custom format. The following statements demonstrate how to export the public part of a key pair and write it out as a pair of hexadecimal strings: # C# // create an instance of the RSA algorithm RSACryptoServiceProvider x_alg = new RSACryptoServiceProvider( ); // export only the public key RSAParameters x_public_params = x_alg.ExportParameters(false); Console.Write("n: "); foreach (byte x_byte in x_public_params.Modulus) { Console.Write("{0:X2} ", x_byte); } Console.WriteLine( ); Console.Write("e: "); foreach (byte x_byte in x_public_params.Exponent) { Console.Write("{0:X2} ", x_byte); } # Visual Basic .NET ' create an instance of the RSA algorithm Dim x_alg As RSACryptoServiceProvider = New RSACryptoServiceProvider( ) ' export only the public key Dim x_public_params As RSAParameters = x_alg.ExportParameters(False) Console.Write("n: ") Dim x_byte As Byte For Each x_byte In x_public_params.Modulus Console.Write("{0:X2} ", x_byte) Next x_byte Console.WriteLine( ) Console.Write("e: ") For Each x_byte In x_public_params.Exponent Console.Write("{0:X2} ", x_byte) Next x_byte The ToXmlString method exports the key information as an XML string, as in the following example: <RSAKeyValue> <Modulus>xCDce...</Modulus> <Exponent>AQAB</Exponent> <P>6heANKwqXC4d...</P> <Q>1nvPzfGay26Q...</Q> <DP>Wxyyhc3M3vw...</DP> <DQ>i0evdC8WtFB...</DQ> <InverseQ>r01lw... </InverseQ> <D>mHKmjx5hjhZn...</D> </RSAKeyValue> The XML string represents each of the values from the RSAParameters structure as a Base64-encoded string; we have shortened the strings shown, which are very long even for a 384-bit key. The ToXmlString method accepts a Boolean argument that includes the private key when set to true and exports only the public key when false. You can import XML strings exported using this method into instances of RSACryptoServiceProvider using the FromXmlString method. 15.2.6 Encrypting and Decrypting DataThe RSACryptoServiceProvider class defines the Encrypt and Decrypt methods, each of which processes a byte array, as demonstrated by the following statements: # C# using System; using System.Security.Cryptography; using System.Text; class RSAExample { static void Main( ) { // define the plaintext to encrypt byte[] x_plaintext = Encoding.Default.GetBytes("Programming .NET Security"); // create an instance of the RSA algorithm RSACryptoServiceProvider x_alg = new RSACryptoServiceProvider( ); // encrypt the plaintext using OAEP padding byte[] x_ciphertext = x_alg.Encrypt(x_plaintext, true); // decrypt the plaintext byte[] x_new_plaintext = x_alg.Decrypt(x_ciphertext, true); // reconstruct a string from the new plaintext and print it out string x_output = Encoding.Default.GetString(x_new_plaintext); Console.WriteLine(x_output); } } # Visual Basic .NET Imports System Imports System.Security.Cryptography Imports System.Text Class RSAExample Shared Sub Main( ) ' define the plaintext to encrypt Dim x_plaintext As Byte( ) _ = Encoding.Default.GetBytes("Programming .NET Security") ' create an instance of the RSA algorithm Dim x_alg As RSACryptoServiceProvider = New RSACryptoServiceProvider( ) ' encrypt the plaintext using OAEP padding Dim x_ciphertext( ) As Byte = x_alg.Encrypt(x_plaintext, True) ' decrypt the plaintext Dim x_New_plaintext( ) As Byte = x_alg.Decrypt(x_ciphertext, True) ' reconstruct a string from the new plaintext and print it out Dim x_output As String = Encoding.Default.GetString(x_New_plaintext) Console.WriteLine(x_output) End Sub End Class The Boolean argument to the Encrypt and Decrypt methods specifies whether to use OAEP padding; if this value is set to false, then PKCS #1 v1.5 padding will be used.
The RSA implementation does not support processing data using the CryptoStream class that we described in Chapter 14. The relatively slow performance of all asymmetric algorithms means that they are rarely used to encrypt large amounts of data and are most frequently employed for "key exchange," which we discuss in Chapter 17. |
[ Team LiB ] |