RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Building Truly Useful Extension Methods  : Page 3

Use extension methods to breathe new life into old classes—even classes that you didn't write!

High-Level Encryption
If you've read my other articles on DevX and elsewhere you probably know that I like tricky code: complex algorithms, three-dimensional graphics, stuff like that. Something as simple as the Left, Right, RemoveLeft, and RemoveRight extension methods just isn't enough. I couldn't finish this article without doing something a bit more interesting.

I've actually wished for a simpler method for encrypting and decrypting strings. The System.Security.Cryptography namespace provides some amazing cryptographic tools, but they're pretty hard to use, so I decided that implementing them as simple string extensions would be useful.

At a fairly high level, here's what the extension methods should look like to someone who wants to use them:

  • To make the encryption tools as flexible as possible, Microsoft made them encrypt and decrypt bytes rather than text. Whether the bytes represent text, images, video, or spreadsheets doesn't matter to the encryption routines. They just chop up the bytes and reassemble them later.
  • The new String class extension method Encrypt will take a password as a parameter and return the string encrypted with that password. The encryption methods return the encrypted string as a byte array, so Encrypt also returns a byte array.
The following code shows the Encrypt extension method. The parameter plain_text is the string that the method should encrypt. The other parameter is the password. The method uses an ASCIIEncoding object to convert the string into a byte array and then calls helper function CryptBytes (which I'll get to a bit later) to encrypt the string and return the resulting byte array.

   ' Encrypt a string into a byte array.
   <Extension()> _
   Public Function Encrypt(ByVal plain_text As String, _
   ByVal password As String) As Byte()
      Dim ascii_encoder As New System.Text.ASCIIEncoding()
      Dim plain_bytes As Byte() = ascii_encoder.GetBytes(plain_text)
      Return CryptBytes(password, plain_bytes, True)
   End Function
Here's how you might use this method to encrypt a string:

   Dim txt As String = "Message"
   Dim bytes() As Byte = txt.Encrypt("SecretPassword")
Encrypting a string is useful only if you can decrypt it later. The following code shows the Decrypt extension method, which reassembles the original string. Notice that this method's first parameter is a byte array, so rather than being a String extension, this method extends the byte array data type. The method calls the CryptBytes helper function to decrypt the byte array (discussed later) to decrypt the bytes, converts the bytes back into a string using an ASCIIEncoding object, and returns the result:

   ' Decrypt a byte array into a string.
   <Extension()> _
   Public Function Decrypt(ByVal encrypted_bytes() As Byte, _
   ByVal password As String) As String
      Dim decrypted_bytes() As Byte = _
         CryptBytes(password, encrypted_bytes, False)
      Dim ascii_encoder As New System.Text.ASCIIEncoding()
      Return ascii_encoder.GetChars(decrypted_bytes)
   End Function
Now, storing an encrypted string in a byte array is okay if you want to store the bytes in a file but you cannot display the bytes on the screen. If you want to visualize the encrypted data, you need a reasonable way to display them in a string. One way to do that is to convert the encrypted byte array into a series of hexadecimal values.

The following BytesToHexString extension method does just that. Its first parameter is a byte array, so that's the data type that it extends. The code loops through the bytes in the array, converts each to hexadecimal, and pads the result to two characters so that small numbers such as A come out as 0A. If the result is non-empty (in other words, the array was not empty), the method removes the leading space character and returns the result:

   ' Return a hexadecimal representation of the bytes.
   <Extension()> _
   Public Function BytesToHexString(ByVal bytes() As Byte) As String
      Dim result As String = ""
      For Each b As Byte In bytes
         result &= " " & Hex(b).PadLeft(2, "0")
      Next b
      If result.Length > 0 Then result = result.Substring(1)
      Return result
   End Function
Now you can write code similar to the following to encrypt a string, convert the encrypted bytes into a string, and save the result in the variable cipher_text.

   Dim txt As String = "Message"
   Dim bytes() As Byte = txt.Encrypt("SecretPassword")
   Dim cipher_text As String = bytes.BytesToHexString()
After storing the encrypted text stored as a string, you need a way to recover the original message. The first step in reversing the encryption is to turn the hexadecimal string back into a byte array. Then you can use the Decrypt extension method to decode the array.

The following code shows the HexStringToBytes extension method. This method's first parameter is a string so it extends the String class. It first removes all spaces from the hexadecimal string, then adds the text &H to the beginning of each pair of letters in the string (each pair represents a byte). Finally, it converts the result into a byte, and stores the byte in a byte array. After processing all the character pairs, it returns the byte array:

   ' Return a byte array initialized with the given
   ' hexadecimal codes.
   <Extension()> _
   Public Function HexStringToBytes(ByVal str As String) As Byte()
      str = str.Replace(" ", "")
      Dim max_byte As Integer = str.Length \ 2 - 1
      Dim bytes(max_byte) As Byte
      For i As Integer = 0 To max_byte
         bytes(i) = CByte("&H" & str.Substring(2 * i, 2))
      Next i
      Return bytes
   End Function
Author's Note: There's a nice symmetry between the BytesToHexString and HexStringToBytes methods. The first extends the byte array data type and returns a string. The second extends the String class and returns a byte array.

By using the Encrypt and BytesToHexString extension methods together, you can now easily write a method that both encrypts a string and returns an encrypted hex string suitable for display. The following code shows the EncryptToString extension method, which does just that. This method simply calls the Encrypt method to get a byte array and then calls the byte array's BytesToHexString method to get a string result:

   ' Encrypt a string into a string of byte values.
   <Extension()> _
   Public Function EncryptToString(ByVal plain_text As String, _
   ByVal password As String) As String
      Return plain_text.Encrypt(password).BytesToHexString()
   End Function
Similarly, by combining the HexStringToBytes and Decrypt methods, you can create a single useful extension method that decrypts a string holding a hexadecimal encryption. The DecryptFromString method shown below calls the encrypted string's HexStringToBytes method to get a byte array, calls the array's Decrypt method, and returns the result:

   ' Decrypt a string of byte values into a string.
   <Extension()> _
   Public Function DecryptFromString( _
   ByVal encrypted_bytes_string As String, _
   ByVal password As String) As String
      Return _
   End Function

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date