The .NET framework includes a rich set of classes for performing cryptographic operations. You can access any of these classes within an ASP.NET page. In several situations, you need to use these classes in an ASP.NET application. For example you can use these classes to encrypt sensitive information, such as credit card numbers and legal documents, before you store the information in a database table or the file system. You also can use these classes to automatically add digital signatures to documents. In the following sections, you learn how to use the cryptography classes to generate hash codes, encrypt data by using both symmetric and asymmetric cryptographic algorithms, and create digital signatures. NOTE Many of the cryptographic classes in the .NET framework are managed wrappers for the Windows Cryptographic Service Providers (CSPs). To use a particular cryptographic class, the proper CSP must be installed. Using Hash AlgorithmsA hash algorithm generates a fixed-length hash value that uniquely represents the contents of an arbitrary length string. Identical strings generate the same hash value. Strings that differ in the smallest respect generate different hash values. Imagine that you have a file that contains the complete text of the Declaration of Independence. You can use a hash algorithm to generate a string of 16 characters that represent the contents of this file. If you change a single letter in the file, the hash algorithm would generate a different hash value. Hash values are useful for detecting changes in a file. They enable you to take a snapshot of the state of a file at any point of time. If you want to know whether a file has been changed on the hard drive, you can compare the file's current hash value to its previous hash value. Hash values can be used to protect data integrity. For example, the Forms authentication module uses hash values to detect changes in the cookie Authentication Tickets that it issues. The classes in the .NET framework support the following hash algorithms:
The MD5 hash algorithm is the fastest but the least secure. Each SHA algorithm is progressively more secure but requires more computation. NOTE The System.Security.Cryptography namespace includes two classes that support keyed hashed algorithms: HMACSHA1 and MACTripleDES . These classes are particularly useful for generating message authentication codes (MACs). You can use any of these classes to compute a hash value by calling the ComputeHash method. This method accepts a byte array that represents the data to be hashed and returns a byte array that represents the hash value. For example, the ASP.NET page in Listing 21.2 returns a hash value by using the MD5 hash algorithm (see Figure 21.4). Listing 21.2 Hash.aspx<%@ Import Namespace="System.Security.Cryptography" %> <Script Runat="Server"> Function Convert2ByteArray( strInput As String ) As Byte() Dim intCounter As Integer Dim arrChar As Char() arrChar = strInput.ToCharArray() Dim arrByte( arrChar.Length - 1 ) As Byte For intCounter = 0 To arrByte.Length - 1 arrByte( intCounter ) = Convert.ToByte( arrChar( intCounter ) ) Next Return arrByte End Function Sub Button_Click( s AS Object, e As EventArgs ) Dim arrHashInput As Byte() Dim arrHashOutput As Byte() Dim objMD5 As MD5CryptoServiceProvider objMD5 = New MD5CryptoServiceProvider arrHashInput = Convert2ByteArray( txtInput.Text ) arrHashOutput = objMD5.ComputeHash( arrHashInput ) lblOutput.Text = BitConverter.ToString( arrHashOutput ) End Sub </Script> <html> <head><title>Hash.aspx</title></head> <body> <form Runat="Server"> <h2>Generate MD5 Hash</h2> <b>Enter text to hash:</b> <br> <asp:TextBox id="txtInput" TextMode="Multiline" Columns="50" Rows="10" Runat="Server" /> <p> <asp:Button Text="Compute Hash!" OnClick="Button_Click" Runat="Server" /> <p> <b>Hash value:</b> <br> <asp:Label ID="lblOutput" Runat="Server" /> </form> </body> </html> The C# version of this code can be found on the CD-ROM. Figure 21.4. Computing a hash value.
The page in Listing 21.2 displays a multiline TextBox control. If you enter text into it and click the submit button, the hash value for the text is displayed. Notice that even a single character difference generates a different hash value. You cannot pass a string directly to the ComputeHash method of any of the Hash classes. In Listing 21.2, the string is converted to a byte array with the Convert2ByteArray function before being passed to the ComputeHash method. The byte array returned by ComputeHash is converted back to a string with the BitConverter class. Using Symmetric Encryption AlgorithmsWhen you think of encryption, you typically think of symmetric encryption algorithms. When you encrypt a message with a symmetric encryption algorithm, both the sender and recipient of the message must share the same decryption key. The classes in the .NET framework support the following symmetric encryption algorithms:
You can use any of these encryption algorithms in your ASP.NET pages. For example, you can encrypt information that users enter into an HTML form and send the information in an email, store the information on the file system, or add the information to a database table. For this next example, you use the DESCryptoServiceProvider class to encrypt form data and store the encrypted data in a file. You need to create two ASP.NET pages: SymmetricWrite.aspx and SymmetricRead.aspx . The SymmetricWrite.aspx page, contained in Listing 21.3, will encrypt and write the data to a file, and the SymmetricRead.aspx page will read and decrypt the data from the file. Listing 21.3 SymmetricWrite.aspx<%@ Import Namespace="System.IO" %> <%@ Import Namespace="System.Security.Cryptography" %> <Script Runat="Server"> CONST DESKey As String = "ABCDEFGH" CONST DESIV As String = "HGFEDCBA" Function Convert2ByteArray( strInput As String ) As Byte() Dim intCounter As Integer Dim arrChar As Char() arrChar = strInput.ToCharArray() Dim arrByte( arrChar.Length - 1 ) As Byte For intCounter = 0 To arrByte.Length - 1 arrByte( intCounter ) = Convert.ToByte( arrChar( intCounter ) ) Next Return arrByte End Function Sub Button_Click( s As Object, e As EventArgs ) Dim arrDESKey As Byte() Dim arrDESIV AS Byte() Dim arrInput As Byte() Dim objFileStream As FileStream Dim objDES As DESCryptoServiceProvider Dim objEncryptor As ICryptoTransform Dim objCryptoStream As CryptoStream arrDESKey = Convert2ByteArray( DESKey ) arrDESIV = Convert2ByteArray( DESIV ) arrInput = Convert2ByteArray( txtInput.Text ) objDES = New DESCryptoServiceProvider() objEncryptor = objDES.CreateEncryptor( arrDESKey, arrDESIV ) objFileStream = New FileStream( _ MapPath( "secret.txt" ), _ FileMode.Create, _ FileAccess.Write ) objCryptoStream = New CryptoStream( _ objFileStream, _ objEncryptor, _ CryptoStreamMode.Write ) objCryptoStream.Write( arrInput, 0, arrInput.Length ) objCryptoStream.Close() End Sub </Script> <html> <head><title>SymmetricWrite.aspx</title></head> <body> <form Runat="Server"> <h2>DES Encryption</h2> <b>Enter text to encrypt:</b> <br> <asp:TextBox id="txtInput" TextMode="Multiline" Columns="50" Rows="10" Runat="Server" /> <p> <asp:Button Text="Encrypt!" OnClick="Button_Click" Runat="Server" /> </form> </body> </html> The C# version of this code can be found on the CD-ROM. The page in Listing 21.3 displays a form with a single TextBox control (see Figure 21.5). If you enter text into it and click the submit button, the form data is encrypted using the DES encryption algorithm and saved to a file named secret.txt. Figure 21.5. Encrypting a file.
Notice the two constants named DESKey and DESIV defined at the top of the file. When you encrypt data with DESCryptoServiceProvider , you must supply both a secret key and an initialization vector. You need to use these two constants to decrypt the file after you create it. In Listing 21.3, the secret key is assigned the value ABCDEFGH , and the initialization vector is assigned the value HGFEDCBA . You should think of these values as the secret passwords to the file. You can assign any eight-character string to these constants. You can decrypt the contents of the secret.txt file by using the ASP.NET page in Listing 21.4 (see Figure 21.6). Listing 21.4 SymmetricRead.aspx<%@ Import Namespace="System.IO" %> <%@ Import Namespace="System.Security.Cryptography" %> <Script Runat="Server"> CONST DESKey As String = "ABCDEFGH" CONST DESIV As String = "HGFEDCBA" Sub Page_load DESDecrypt End Sub Function Convert2ByteArray( strInput As String ) As Byte() Dim intCounter As Integer Dim arrChar As Char() arrChar = strInput.ToCh arArray() Dim arrByte( arrChar.Length - 1 ) As Byte For intCounter = 0 To arrChar.Length - 1 arrByte( intCounter ) = Convert.ToByte( arrChar( intCounter ) ) Next Return arrByte End Function Sub DESDecrypt Dim arrDESKey As Byte() Dim arrDESIV As Byte() Dim objFileStream As FileStream Dim objDES As DESCryptoServiceProvider Dim objDecryptor As ICryptoTransform Dim objCryptoStream As CryptoStream arrDESKey = Convert2ByteArray( DESKey ) arrDESIV = Convert2ByteArray( DESIV ) objDES = New DESCryptoServiceProvider objDecryptor = objDES.CreateDecryptor( arrDESKey, arrDESIV ) objFileStream = New FileStream( _ MapPath( "secret.txt" ), _ FileMode.Open, _ FileAccess.Read ) objCryptoStream = New CryptoStream( _ objFileStream, _ objDecryptor, _ CryptoStreamMode.Read ) lblMessage.Text = New StreamReader( objCryptoStream ).ReadToEnd() objFileStream.Close End Sub </Script> <html> <head><title>SymmetricRead.aspx</title></head> <body> <h2>DES Decryption</h2> <b>Decrypted Text:</b> <p> <asp:Label ID="lblMessage" Runat="Server" /> </body> </html> The C# version of this code can be found on the CD-ROM. Figure 21.6. Decrypting a file.
The page in Listing 21.4 reads, decrypts, and displays the contents of the secret.txt file in the DESDecrypt subroutine. Notice that the DESKey and DESIV constants are defined at the top of the page. The values of these constants in this page must match the values of these constants in the SymmetricWrite.aspx page. Using Asymmetric EncryptionWhen you use a symmetric encryption algorithm, both the sender and recipient of a message must share a common decryption key. You use the same secret key to encrypt a message as the key that you use to decrypt the message. When you use an asymmetric encryption algorithm, on the other hand, the key used to encrypt a message is distinct from the key used to decrypt the message. Asymmetric encryption algorithms use a key pair. If you encrypt a message with one key, you need the other key to decrypt the message. Asymmetric encryption algorithms often are used to create digital signatures. Typically, one key is made public, and the other key is kept private. If you encrypt a message with your private key, it can be decrypted only with your public key. If you send another user a message encrypted with your private key, that user can verify that you sent the message by decrypting it with your public key. NOTE Asymmetric algorithms are often referred to as public key algorithms . When used with a hash algorithm, an asymmetric algorithm can detect whether a message has been altered. For example, if George needs to send Jane a message, and George and Jane need to ensure that the message has not been altered in transit, the two of them can do the following:
The classes in the .NET framework support the following two asymmetric algorithms:
Both algorithms implement the AsymmetricAlgorithm class, so they share many of the same methods and properties. If you create an instance of either class, the private and public keys are automatically generated. You can access the public or private key by using either the ToXmlString or ExportParameters method. The ToXmlString method represents the public and private keys with an XML string. The following sample statements create an instance of the DSACryptoServiceProvider class and display the private and public keys: Dim objDSA As New DSACryptoServiceProvider() Response.Write( "<h2>Private Key:</h2>" ) Response.Write( Server.HTMLEncode( objDSA.ToXmlString( True ) ) ) Response.Write( "<h2>Public Key:</h2>" ) Response.Write( Server.HTMLEncode( objDSA.ToXmlString( False ) ) ) Notice that you use the ToXmlString method to display both the private and public keys. You pass the value True to display the private key and the value False to display the public key. The preceding statements generate output similar to the following: Private Key: <DSAKeyValue><P>1AYChM6ITZ1sFQDtDd8rfDNAoeWdIttEpgY53xArTjl1RrZ7LD887IQFRmY CqCjgA0EoToR8elnIbAsr+IGN9h4dRnbKaCk/LupXj1bxJqQbMlqXyfLehxeshRCgajFqAOmMW6 SSlNNdJU8DY8gzPUzSar57UhpbDur1p2MHwlc=</P><Q>5RdZjO/s6pJMQEOnzThKX0/EJp8=</ Q><G>sQNgfhRtZ5GGufpdPgb5zYAP0go4egcNhGibQbIV4OBgqP2jiBLURjnxSHNs5GKbvUGT2t 5Sr2DP8+704Tv+osjNtOsG324Txgdx3Li0wsqguyBu2stlIPI2FxPuTcasLqPmFuWhBHexFT2lg 4w4eVCVH1jlaCZ7lmrI1ux2w2c=</G><Y>FlAgexkYEnPIM06dnGmE5s/mj/7M9V1ohQY+ZH80d LTOWCobBt7T16ToR0dUpcIHDrn7kha5Bj4YnT6pjAr55VtclBu3td8m6M3Ymm8MqLQXTVj9aWem nrHVX+/hMNXOnBGsaf/Lrvjw37TERKocTzJcV9Jv2tsaklC9nQeSx3I=</Y><J>7O1xQHFufGn5 X592ZJ90kuRA/RzxZltsiULtfuNaBu95uNaAYHKOajkBJQP8/U4jzoYvPOTYw9Z37r8BLt8Vt8Q p64IkmlqHMwlFVZhYU/XNwuXfrSdUPxwl6s+eZHe4GKr4H1vz49wTaGvq</J><Seed>b3M+ieba mm7xgDEZmUJ2QNB1elg=</Seed><PgenCounter>ARM=</PgenCounter><X>iJMgNkrX+Wj4pV eSc1VPV2fOBPg=</X></DSAKeyValue> Public Key: <DSAKeyValue><P>1AYChM6ITZ1sFQDtDd8rfDNAoeWdIttEpgY53xArTjl1RrZ7LD887IQFRmY CqCjgA0EoToR8elnIbAsr+IGN9h4dRnbKaCk/LupXj1bxJqQbMlqXyfLehxeshRCgajFqAOmMW6 SSlNNdJU8DY8gzPUzSar57UhpbDur1p2MHwlc=</P><Q>5RdZjO/s6pJMQEOnzThKX0/EJp8=</ Q><G>sQNgfhRtZ5GGufpdPgb5zYAP0go4egcNhGibQbIV4OBgqP2jiBLURjnxSHNs5GKbvUGT2t 5Sr2DP8+704Tv+osjNtOsG324Txgdx3Li0wsqguyBu2stlIPI2FxPuTcasLqPmFuWhBHexFT2lg 4w4eVCVH1jlaCZ7lmrI1ux2w2c=</G><Y>FlAgexkYEnPIM06dnGmE5s/mj/7M9V1ohQY+ZH80d LTOWCobBt7T16ToR0dUpcIHDrn7kha5Bj4YnT6pjAr55VtclBu3td8m6M3Ymm8MqLQXTVj9aWem nrHVX+/hMNXOnBGsaf/Lrvjw37TERKocTzJcV9Jv2tsaklC9nQeSx3I=</Y><J>7O1xQHFufGn5 X592ZJ90kuRA/RzxZltsiULtfuNaBu95uNaAYHKOajkBJQP8/U4jzoYvPOTYw9Z37r8BLt8Vt8Q p64IkmlqHMwlFVZhYU/XNwuXfrSdUPxwl6s+eZHe4GKr4H1vz49wTaGvq</J><Seed>b3M+ieba mm7xgDEZmUJ2QNB1elg=</Seed><PgenCounter>ARM=</PgenCounter></DSAKeyValue> If you look closely at the private and public keys, you notice that they differ in a final <X> element, which represents the private key. You can use the SignData method to generate a digital signature for a message. This method accepts one parameter: a byte array representing the message to be signed. The SignHash method returns a byte array that represents the digital signature for the message. The VerifyData method performs the opposite operation. You can use this method to verify that a message matches its digital signature. It accepts two parameters: a byte array representing the data to verify and a byte array that represents the digital signature. VerifyData returns the value True when the message matches the signature and False otherwise . The page in Listing 21.5, for example, generates a digital signature for any text that you enter into an HTML form (see Figure 21.7). Listing 21.5 AsymmetricWrite.aspx<%@ Import Namespace="System.Security.Cryptography" %> <Script Runat="Server"> Function Convert2ByteArray( strInput As String ) As Byte() Dim intCounter As Integer Dim arrChar As Char() arrChar = strInput.ToCharArray() Dim arrByte( arrChar.Length - 1 ) As Byte For intCounter = 0 To arrByte.Length - 1 arrByte( intCounter ) = Convert.ToByte( arrChar( intCounter ) ) Next Return arrByte End Function Sub Button_Click( s As Object, e As EventArgs ) Dim arrInput As Byte() Dim objDSA As DSACryptoServiceProvider Dim strPublicKey As String Dim arrDigitalSignature As Byte() arrInput = Convert2ByteArray( txtInput.Text ) objDSA = New DSACryptoServiceProvider() strPublicKey = objDSA.ToXMLString( False ) arrDigitalSignature = objDSA.SignData( arrInput ) txtSignature.Text = BitConverter.ToString( arrDigitalSignature ) txtPublicKey.Text = strPublicKey End Sub </Script> <html> <head><title>AsymmetricWrite.aspx</title></head> <body> <H2>Create Digital Signature</h2> <form Runat="Server"> <asp:TextBox ID="txtInput" TextMode="Multiline" Columns="60" Rows="3" Runat="Server" /> <p> <asp:Button Text="Create Signature!" OnClick="Button_Click" Runat="Server" /> <p> Digital Signature: <br> <asp:TextBox ID="txtSignature" TextMode="Multiline" Columns="60" Rows="4" Runat="Server" /> <p> Public Key: <br> <asp:TextBox ID="txtPublicKey" TextMode="Multiline" Columns="60" Rows="10" Runat="Server" /> </form> </body> </html> The C# version of this code can be found on the CD-ROM. Figure 21.7. Generating a digital signature.
When you enter text into the TextBox control in Listing 21.5 and submit the form, the Button_Click subroutine generates a digital signature by using RSACryptoServiceProvider . The Button_Click subroutine displays the digital signature and the public key associated with the digital signature in two TextBox controls. The page in Listing 21.6 performs the opposite operation. This page uses the VerifyData method to verify that a message matches a digital signature associated with a particular public key (see Figure 21.8). Listing 21.6 AsymmetricRead.aspx<%@ Import Namespace="System.Globalization" %> <%@ Import Namespace="System.Security.Cryptography" %> <Script Runat="Server"> Function Convert2ByteArray( strInput As String ) As Byte() Dim intCounter As Integer Dim arrChar As Char() arrChar = strInput.ToCharArray() Dim arrByte( arrChar.Length - 1 ) As Byte For intCounter = 0 To arrByte.Length - 1 arrByte( intCounter ) = Convert.ToByte( arrChar( intCounter ) ) Next Return arrByte End Function Function ConvertHexArray( strInput As String ) As Byte() Dim intCounter As Integer Dim arrString As String() arrString = strInput.Split( New Char() { "-" } ) Dim arrByte( arrString.Length - 1 ) As Byte For intCounter = 0 To arrByte.Length - 1 arrByte( intCounter ) = Byte.Parse( arrString( intCounter ), NumberStyles.HexNumber ) Next Return arrByte End Function Sub Button_Click( s As Object, e As EventArgs ) Dim arrInput As Byte() Dim objDSA As DSACryptoServiceProvider Dim strPublicKey As String Dim arrDigitalSignature As Byte() arrInput = Convert2ByteArray( txtInput.Text ) arrDigitalSignature = ConvertHexArray( txtSignature.Text ) objDSA = New DSACryptoServiceProvider() objDSA.FromXMLString( txtPublicKey.Text ) lblVerify.Text = objDSA.VerifyData( arrInput, arrDigitalSignature ) End Sub </Script> <html> <head><title>AsymmetricRead.aspx</title></head> <body> <H2>Verify Digital Signature</h2> <form Runat="Server"> Message: <br> <asp:TextBox ID="txtInput" TextMode="Multiline" Columns="60" Rows="3" Runat="Server" /> <p> Digital Signature: <br> <asp:TextBox ID="txtSignature" TextMode="Multiline" Columns="60" Rows="4" Runat="Server" /> <p> Public Key: <br> <asp:TextBox ID="txtPublicKey" TextMode="Multiline" Columns="60" Rows="10" Runat="Server" /> <p> <asp:Button Text="Verify Signature!" OnClick="Button_Click" Runat="Server" /> <p> Verified? <br> <asp:Label ID="lblVerify" Runat="Server" /> </form> </body> </html> The C# version of this code can be found on the CD-ROM. Figure 21.8. Verifying a digital signature.
The page in Listing 21.6 displays a form with three TextBox controls: one for a message, one for a digital signature, and one for a public key. If you enter this information and click the verify button, the page returns the value True if the message can be verified and the value False otherwise. |