Export (0) Print
Expand All

Cryptography Simplified in Microsoft .NET

 

Paul D. Sheriff
PDSA.com

October 2003

Applies to:
   Microsoft® .NET
   Security
   Microsoft® Visual Basic® .NET
   C#

Summary: Learn how to leverage the Cryptography features in the .NET Framework to protect your data by creating a wrapper similar to the one shown in this article. (21 printed pages)

Download the CryptoSampleCSSample.msi and the CryptoSampleVBSample.msi code samples associated with this article.

Download the CryptoSampleCSSample.msi code sample.

Download the CryptoSampleCSSample.msi code sample.

Contents

Corn Beef Hash
Create Sample Hash Projects
Add Some Salt to Your Hash
Summary

Do you have secrets that you would like to keep on your computer? If so, then cryptography is for you! Cryptography is the science of scrambling meaningful characters into non-meaningful characters so as not to be read by people that should not have access to the data. The science of cryptography has been around for many years, even long before computers. With the advent of computers, however, the science was able to produce almost unbreakable codes. Microsoft developed and distributed the Cryptography API in Windows 95. With Microsoft .NET, newly created classes wrap up these sophisticated algorithms into fairly easy-to-use properties and methods.

Corn Beef Hash

If all you wish to do is to keep a password safe from prying eyes, then you might create a hash of the data. A hash is a one-way algorithm that once the data has been transformed, it is impossible to ever retrieve the original value. Most developers use a database to store a password. However, someone looking at the user data in the database will see the passwords. Instead you hash the password and store that in the database. When the user enters the user password, you can hash it again and compare that hash to the hash stored in the database. Another by-product of hashing is that even a small change in the original data will produce a widely varying hash of that data. The two words, Pork and Porky, when hashed, will produce very different outputs. It would be impossible to see any resemblance between them.

There are several hashing algorithm classes available to the .NET developer. The most commonly used ones are SHA1 and MD5. Let's take a look at how you can take an ordinary string like "Paul" and create a hash out of it, so it is completely unrecognizable to anyone.

Use SHA1 to Cook Hash

Let's create a new routine that will hash the string "Paul". Open a new Windows Application in Visual Studio® .NET, and drop a command button on a form. In the Click event of this command button, call a method named HashText(). Below is the code that you can add to this form to try out this hashing algorithm. Before writing this code you will need to import the namespace System.Security.Cryptography.

Private Sub HashText(ByVal TextToHash As String)
  Dim SHA1 As SHA1CryptoServiceProvider
  Dim bytValue() As Byte
  Dim bytHash() As Byte

  ' Create New Crypto Service Provider Object
  SHA1 = New SHA1CryptoServiceProvider

  ' Convert the original string to array of Bytes
  bytValue = _
   System.Text.Encoding.UTF8.GetBytes(TextToHash)

  ' Compute the Hash, returns an array of Bytes
  bytHash = SHA1.ComputeHash(bytValue)

  SHA1.Clear()

  ' Return a base 64 encoded string of the Hash value
  Debug.WriteLine(Convert.ToBase64String(bytHash))
End Sub

You can call this routine passing in different string values to see the hashed value. For example, if you pass in the string "Paul" to this routine, the Debug window will display the text:

w2h6uYgMJt/nq5ZqihcBteAXwv8=

Now change the input value to this procedure to "Pauly". You will see the following output:

proywxJ0znMpGF5sbB18+7GSAsM=

As you can see, just a small difference in the input string produces a totally different combination of characters. This is what makes hashing so effective, is it makes it very difficult to spot patterns or try to figure out what the original string was from the encrypted characters.

MD5 Also Cooks Hash

Once you learn to use one hashing class, you have basically learned them all. The following method is for the MD5 hashing algorithm. Notice that the code is identical except for the different CryptoServiceProvider class.

Private Sub HashTextMD5(ByVal TextToHash As String)
  Dim md5 As MD5CryptoServiceProvider
  Dim bytValue() As Byte
  Dim bytHash() As Byte

  ' Create New Crypto Service Provider Object
  md5 = New MD5CryptoServiceProvider

  ' Convert the original string to array of Bytes
  bytValue = System.Text.Encoding. _
   UTF8.GetBytes(TextToHash)

  ' Compute the Hash, returns an array of Bytes
  bytHash = md5.ComputeHash(bytValue)

  md5.Clear()

  ' Return a base 64 encoded string of the Hash value
  Debug.WriteLine(Convert.ToBase64String(bytHash))
End Sub

With the input of "Paul", the output from the MD5 hashing algorithm is the following:

nVWBsHh1MKNctPioSyqyTQ==

Once again, this encrypted string looks very different from the original input. Using these hashing algorithms is very good for creating passwords that do not mean anything and would be very difficult for hackers to guess on their own. You use hashing algorithms since you can hash the password and store that in a database. Then when the user inputs the real password, you hash it first, and then send it across the network to see if it matches to what is in the database. Remember that hashing is a one-way operation. You will never be able to recover the original password once it has been hashed.

How to Choose an Algorithm

Each one of the hashing algorithms presented performs the same type of operation. The differences between them are simply in the size of the key used to produce the hash. The larger the key used, the stronger the encryption. For example, SHA1 uses a 160-bit encryption key, whereas MD5 uses a 128-bit encryption key; thus, SHA1 is more secure than MD5 and thus is a much harder hash to break.

Another point to consider about hashing algorithms is whether or not there are practical or theoretical possibilities of collisions. Collisions are bad since two different words could produce the same hash. SHA1, for example, has no practical or theoretical possibilities of collision. MD5 has the possibility of theoretical collisions, but no practical possibilities. So choosing an algorithm comes down to the level of security you need.

Create Sample Hash Projects

There are two sample hashing projects included with this article to demonstrate in a more generic manner how you can encrypt any string using different hashing algorithms. The two sample projects are entitled CryptoSampleVB.sln and CryptoSampleCS.sln. CryptoSampleVB is a Visual Basic .NET solution and CryptoSampleCS is a C# solution. Both solutions include a form that looks like Figure 1 that will allow you to input an original string to be hashed, an option button to choose the hashing algorithm to use, and a text box to display the resulting hash.

Ff649032.cryptosimplified_01(en-us,PandP.10).gif

Figure 1. Create a generic hash screen to test out a couple of hashing algorithms.

When you click on the Hash button on this screen, it will run the Click event procedure for that button. This event procedure will call a routine named HashString().

' Visual Basic .NET
Private Sub btnHash_Click(ByVal sender As System.Object, _
 ByVal e As System.EventArgs) Handles btnHash.Click
  txtHashed.Text = HashString(txtOriginal.Text)
End Sub
// C#
private void cmdHash_Click(object sender, 
 System.EventArgs e)
{
   txtHashed.Text = HashString(txtOriginal.Text);
}

The HashString() method takes the input value and calls the SetHash() method. This method will determine, based on the setting of the option buttons on the form, which cryptography service provider to create an instance of and return to the method. A member variable for this form is created named mHash that is of the type HashAlgorithm. The HashAlgorithm type is the base class from which all hashing cryptography service providers are created.

' Visual Basic .NET
Private mhash As HashAlgorithm

// C#
private HashAlgorithm mhash;

The SetHash() method looks like the following:

' Visual Basic .NET
Private Function SetHash() As HashAlgorithm
  If optSHA1.Checked Then
    Return New SHA1CryptoServiceProvider
  Else
    If optMD5.Checked Then
      Return New MD5CryptoServiceProvider
    End If
  End If
End Function

// C#
private HashAlgorithm SetHash()
{
   if(this.optSHA1.Checked)
      return new SHA1CryptoServiceProvider();
   else
      return new MD5CryptoServiceProvider();
}

Based on the option button you choose on the form, a different HashAlgorithm type will be created and returned from this method. The HashString() method performs the actual encryption of the data on this form:

' Visual Basic .NET
Private Function HashString(ByVal Value As String) _
 As String
  Dim bytValue() As Byte
  Dim bytHash() As Byte

  ' Create New Crypto Service Provider Object
  mhash = SetHash()

  ' Convert the original string to array of Bytes
  bytValue = System.Text.Encoding.UTF8.GetBytes(Value)

  ' Compute the Hash, returns an array of Bytes
  bytHash = mhash.ComputeHash(bytValue)

  mhash.Clear()

  ' Return a base 64 encoded string of the Hash value
  Return Convert.ToBase64String(bytHash)
End Function


// C#
private string HashString(string Value)
{
   mhash = SetHash();

   // Convert the original string to array of Bytes
   byte[] bytValue = System.Text.Encoding.UTF8.GetBytes(Value);

   // Compute the Hash, returns an array of Bytes
   byte[] bytHash = mhash.ComputeHash(bytValue);

   mhash.Clear();

   // Return a base 64 encoded string of the Hash value
   return Convert.ToBase64String(bytHash);
}

In the HashString method you created two Byte arrays. The first array is to hold the original string input by the user. You will convert the string to the Byte array using the System.Text.Encoding.UTF8.GetBytes() method. Once you have the original string converted to an array of bytes, you can now compute the hash from this string using the service provider's ComputeHash() method. This method accepts an array of bytes as the input, and will return an array of bytes of the string in their encrypted format.

Note   It is always a good idea to clear the hash variable once you are done with it. Thus you see the call to the Clear method after you have computed the hash for this string.

You now have the array of encrypted bytes and this is what you will return from this method. Since you want to deal with all of your original and encrypted values as String data types instead of Byte arrays, you will return the encrypted bytes by using the Convert.ToBase64String method. This method is responsible for converting an array of bytes into a Base64-encoded string. It is important to use a Base64 encoding in case you need to push this string out on a Web page, or to store it into a database. If you do not convert it, you may have some high-order ASCII characters in the encrypted string that do not display or store correctly.

Add Some Salt to Your Hash

One of the problems with the Hash algorithms presented thus far is that if two users happen to use the same password, the hash will become exactly the same value. If a hacker looks at your table that stores passwords, the hacker will find patterns and know that most likely people are using common words and the hacker can then start a dictionary attack to try to determine the passwords. One way to ensure that no two user's passwords hash to the same value is to add a unique value to each person's password before hashing it. This unique value is called a "salt" value. When you do this you will need to ensure that you store the salt value used as a part of the user's record. I would recommend that if you are using a table to store the user's id and password, that you use a different table to store the salt values. This will give you one extra level of protection in case your database is compromised.

There are many ways to add this salt value to each user's password. An easy method is to take some other information from the user such as their last name, first name, e-mail address, or employee id and concatenate this to the user password, then perform the hashing. The disadvantage to this method is since you need to store the salt value, if the hacker finds this value, the hacker will know what you have done. Of course, this will take the hacker some extra time to figure out, but it is a common technique.

Another method would be to create a random string of digits using the .NET Framework class RNGCryptoServiceProvider. RNG stands for Random Number Generator. This class will create a random array of bytes of any length you specify. You can use this random array of bytes as the salt value for your hashing algorithm. If you do this you will have to securely store this salt value.

In the next example shown in Figure 2, you will input a string into a text box, choose a specific hashing type, and generate a Salt value along with the hash value that is a concatenation of the salt and the original string.

Figure 2. Hash values with salt to create more secure hashes of passwords
(You will need to store the salt value to be able to recreate the same hash.)

This example is exactly the same as the previous example in this article, except for the routine to create the salt value. Under the Click event for the button on this screen you will first call a method named CreateSalt() to generate a unique salt value and store that value into the txtSalt text box. Once you have this unique value, you then call the HashString() method with the concatenation of these two values together.

' Visual Basic .NET
Private Sub btnHash_Click(ByVal sender As System.Object, _
 ByVal e As System.EventArgs) Handles btnHash.Click
  txtSalt.Text = CreateSalt()
  txtHashed.Text = HashString(txtSalt.Text & _
   txtOriginal.Text)
End Sub

// C#
private void cmdHash_Click(object sender, System.EventArgs e)
{
    txtSalt.Text = CreateSalt();
   txtHashed.Text = HashString(txtOriginal.Text);
}

The code for the CreateSalt() method is fairly simple. It first creates an array of bytes that is 8 bytes long. You then create a new instance of the RNGCryptoServiceProvider class. Using the GetBytes() method of this object you will fill in the array of bytes with the generated random set of characters. This array of bytes is then converted to a base 64-encoded string and returned from this function.

' Visual Basic .NET
Private Function CreateSalt() As String
  Dim bytSalt(8) As Byte
  Dim rng As New RNGCryptoServiceProvider

  rng.GetBytes(bytSalt)

  Return Convert.ToBase64String(bytSalt)
End Function

// C#
private string CreateSalt()
{
  byte[] bytSalt = new byte[8];
  RNGCryptoServiceProvider rng;

  rng = new RNGCryptoServiceProvider();

  rng.GetBytes(bytSalt);

  return Convert.ToBase64String(bytSalt);
}

Encryption of Data is a Two-Way Street

If you need to be able to send messages back and forth between two or more people or computers, and you want the other party to be able to read the data, but no one else, then encryption is the way to go! Encryption algorithms allow you to disguise the data in such a way that it is mathematically improbable for anyone other than the intended person to be able to decipher it. However, you can give the people you want to read the data a certain "key" that will be able to decrypt the data so that it is readable again. There are several encryption/decryption algorithms available in the .NET Framework for you to use. This article focuses on symmetric algorithms, and they are:

  • DES
  • RC2
  • Rijndael
  • TripleDES

Symmetric algorithms (or secret-key algorithms) use one key and one Initialization Vector (IV) to keep the data secure. This one key and initialization vector must be known by both parties in order to be able to encrypt and decrypt the data. It is imperative that this key remains secret or anyone will be able to decrypt the data and read the messages. An initialization vector is simply a randomly generated set of characters that is used so no two pieces of text will generate to the same encrypted data. A key can be derived using built-in methods of the different cryptographic classes in .NET. How a key is derived, however, is beyond the scope of this article.

The other type of encryption algorithm is called an asymmetric algorithm. The asymmetric algorithm uses a public/private key pair to create the encrypted data. Asymmetric algorithms will be discussed in the following section.

Where to use which cryptography methods

Symmetric, or secret key, algorithms are extremely fast and are well suited for encrypting large streams of data. These algorithms both encrypt and decrypt data. While these are fairly secure, they do have the potential to be broken given enough time, as someone could do a search on every known key value combination. Since each of these algorithms uses a fixed key length or ASCII characters, it is feasible that a computer program could try every possible combination of keys and eventually stumble onto the right one. A common use of these types of algorithms is for storing and retrieving connection strings to databases.

Asymmetric, or public key, algorithms are not as fast as symmetric, but are much harder codes to break. These algorithms rely on two keys, one is Private and the other is Public. The public key is used to encrypt a message. The Private key is the only one that can decrypt the message. The public and private keys are mathematically linked and thus both are needed for this cryptographic exchange to occur successfully. Asymmetric algorithms are not well suited to large amounts of data due to performance. One common use of asymmetric algorithms is to encrypt and transfer to another party a symmetric key and initialization vector. The symmetric algorithm is then used for all messages being sent back and forth.

Hash values are used when you do not wish to ever recover the original value and you especially wish for no one else to discover the original value as well. Hashes will take any arbitrary string length and hash it to a fixed set of bytes. This operation is one-way, and thus is typically used for small amounts of data, like a password. If a user inputs a user password into a secure entry screen, the program can hash this value and store the hashed value into a database. Even if the database were compromised, no one would be able to read the password since it was hashed. When the user then logs into the system to gain entry, the password typed in is hashed using the same algorithm, and if the two hashed values match, then the system knows the input value was the same as the saved value from before.

Trying out encyption

The sample applications include a form that allows you to try out encryption using the DES and TripleDES cryptographic service providers. The form name is frmEncrypt and looks like that shown in Figure 3.

Ff649032.cryptosimplified_03(en-us,PandP.10).gif

Figure 3. Encryption algorithms allow you to encrypt and decrypt values.

On this screen you will need to first click the Gen Key button, and then click the Gen IV button. Then enter some data into the Original String text box and click the Encrypt button. Once you click the Encrypt button the encrypted text will show up in the Encrypted String text box. If you wish to use this encrypted string in your application, you will need to record the generated Key and generated IV, as you will need to supply those in order to decrypt your connection string so you can use it again. If you lose the key and IV, then you will never be able to recover the connection string again.

Let's now take a look at the code behind this screen to learn how to implement the encryption and decryption routines. To start, let's look at the member variable of this class that will hold a reference to the appropriate cryptographic service provider. This member variable is of the type SymmetricAlgorithm. All symmetric algorithm classes inherit from this base class.

' Visual Basic .NET
Private mCSP As SymmetricAlgorithm
// C#
private SymmetricAlgorithm mCSP;

This mCSP variable will be assigned to a specific symmetric algorithm class based on which option button you choose on this form. The method SetEnc() will take care of creating and returning the appropriate type to the different methods.

' Visual Basic .NET
Private Function SetEnc() As SymmetricAlgorithm
  If optDES.Checked Then
    Return New DESCryptoServiceProvider
  Else
    If optTripleDES.Checked Then
      Return New TripleDESCryptoServiceProvider
    End If
  End If
End Function

// C#
private SymmetricAlgorithm SetEnc()
{
   if(optDES.Checked)
      return new DESCryptoServiceProvider();
   else
      return new TripleDESCryptoServiceProvider();
}

As you can see you will either create a DESCryptoServiceProvider or a TripleDESCryptoServiceProvider object based on which option button you choose on the form.

Keys to the Kingdom

To use a symmetric algorithm you must supply a key to use. Each of the CryptoSymmetricAlgorithm implementations supplies a GenerateKey method. Each of these actually uses a Random Number Generator class built into the common language runtime (CLR) classes. Let's take a look at the Gen Key button's Click event handler to see how it generates a random key value to use.

' Visual Basic .NET
Private Sub btnKeyGen_Click(ByVal sender As _
 System.Object, ByVal e As System.EventArgs) _
 Handles btnKeyGen.Click
  mCSP = SetEnc()

  mCSP.GenerateKey()

  txtKey.Text = Convert.ToBase64String(mCSP.Key)
End Sub
// C#
private void btnKeyGen_Click(object sender, 
 System.EventArgs e)
{
   mCSP = SetEnc();

   mCSP.GenerateKey();

   txtKey.Text = Convert.ToBase64String(mCSP.Key);
}

After getting a specific implementation of the service provider, you simply invoke the GenerateKey method to create a new random key to use for the encryption. The size of the key depends on the specific provider you use for the encryption. For example, the DES key size is 64 bits, while the TripleDES uses a 192-bit key. There is a KeySize property on each SymmetricAlgorithm class that will return the size of the key used to generate the secret key.

You will also need to generate an Initialization Vector (IV). This IV will help the algorithm generate the blocks of data for the final encrypted string. This IV is used to start the encryption of the first block. If you do not provide an IV, then any common data from one string to another would have the same pattern given the same key. Thus, an IV is used as a "random" component to encrypt the data. This way, even if you used the same key, as long as you use a different IV, the same data will be encrypted to some value totally different. Here is the code under the Gen IV button that generates a new IV.

' Visual Basic .NET
Private Sub btnIVGen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnIVGen.Click
  mCSP.GenerateIV()

  txtIV.Text = Convert.ToBase64String(mCSP.IV)
End Sub

// C#
private void btnIVGen_Click(object sender, 
 System.EventArgs e)
{
   mCSP.GenerateIV();

   txtIV.Text = Convert.ToBase64String(mCSP.IV);
}

This code looks very similar to the code to generate a key. There is a GenerateIV() method on each of the crypto service provider classes. This method is responsible for generating an IV if you have not provided one.

Encrypt the Data

Once you have a key and an initialization vector, you may now use the Key, the IV and the Original String values to create an encrypted version of the original string value. When you click the Encrypt button, the following code will be run.

' Visual Basic .NET
Private Sub btnEncrypt_Click( _
 ByVal sender As System.Object, _
 ByVal e As System.EventArgs) Handles cmdEncrypt.Click
  txtEncrypted.Text = EncryptString(txtOriginal.Text)
End Sub

// C#
private void cmdEncrypt_Click(object sender, System.EventArgs e)
{
   txtEncrypted.Text = EncryptString(txtOriginal.Text);
}

The Click event procedure will call a method named EncryptString() to take the value from the Original String text box and encrypt it. It will then return that value and place it into the Encrypted String text box. Below is the code for the EncryptString() method.

' Visual Basic .NET
Private Function EncryptString(ByVal Value As String) _
 As String
  Dim ct As ICryptoTransform
  Dim ms As MemoryStream
  Dim cs As CryptoStream
  Dim byt() As Byte

  ct = mCSP.CreateEncryptor(mCSP.Key, mCSP.IV)

  byt = Encoding.UTF8.GetBytes(Value)

  ms = New MemoryStream
  cs = New CryptoStream(ms, ct, CryptoStreamMode.Write)
  cs.Write(byt, 0, byt.Length)
  cs.FlushFinalBlock()

  cs.Close()

  Return Convert.ToBase64String(ms.ToArray())
End Function

// C#
private string EncryptString(string Value)
{
  ICryptoTransform ct;
  MemoryStream ms;
  CryptoStream cs;
  byte[] byt;

  ct = mCSP.CreateEncryptor(mCSP.Key, mCSP.IV);

  byt = Encoding.UTF8.GetBytes(Value);

  ms = new MemoryStream();
  cs = new CryptoStream(ms, ct, CryptoStreamMode.Write);
  cs.Write(byt, 0, byt.Length);
  cs.FlushFinalBlock();

  cs.Close();

  return Convert.ToBase64String(ms.ToArray());
}

Let's break down each line and look at what it does. You first need a few variables for the encryption process.

Dim ct As ICryptoTransform
Dim ms As MemoryStream
Dim cs As CryptoStream
Dim byt() As Byte

The ICryptoTransform is an interface. You will need this so you can call the CreateEncryptor method on any of the service providers and they will return an actual encryptor object that has this interface defined.

Next you need to convert the original string into an array of bytes. Most of the .NET cryptographic algorithms deal with arrays of bytes instead of strings.

byt = Encoding.UTF8.GetBytes(Value)

Now you are ready to perform the actual encryption. This process involves creating a stream in which to write the encrypted bytes. You will use a MemoryStream object named ms, along with the ICryptoTransform object which is given to the constructor of the CryptoStream class along with an enumerated constant that describes what mode you wish to create this class in (read, write, etc.). Once the CryptoStream object, cs, is created, you can now write the data into the memory stream using the Write method of the CryptoStream object. This method is the one that does the actual encryption, and as it encrypts each block of data, that data is written into the MemoryStream object.

ms = New MemoryStream
cs = New CryptoStream(ms, ct, CryptoStreamMode.Write)
cs.Write(byt, 0, byt.Length)
cs.FlushFinalBlock()

cs.Close()

Once the MemoryStream has been created, the code performs a FlushFinalBlock method on the CryptoStream object to ensure all the data has been written into the MemoryStream object. The procedure closes the CryptoStream object.

Finally, the procedure converts the memory stream from an array of bytes back into a string so that it can display the string within the text box on the form. You can use the MemoryStream ToArray() method to get the array of bytes out of the stream, then call the Convert.ToBase64String() method, which takes as input a byte array and will Base64 encode that string into something that is readable.

Decrypting your Data

After you have encrypted the data, you will need to get the data back at some time. The process of decrypting the data is fairly straightforward and is similar to the encryption process. You will need to supply the same key and initialization vector as the ones used to perform the encryption. The Key and IV properties of the SymmetricAlgorithm classes are defined as Byte arrays. So you will need to take the string you created and convert them to byte arrays prior to setting these properties. Let's take a look at the DecryptString method within the form that will decrypt the string. This method is called from the Click event handler of the Decrypt button on the form.

' Visual Basic .NET
Private Function DecryptString(ByVal Value As String) _
 As String
  Dim ct As ICryptoTransform
  Dim ms As MemoryStream
  Dim cs As CryptoStream
  Dim byt() As Byte

  ct = mCSP.CreateDecryptor(mCSP.Key, mCSP.IV)

  byt = Convert.FromBase64String(Value)

  ms = New MemoryStream
  cs = New CryptoStream(ms, ct, CryptoStreamMode.Write)
  cs.Write(byt, 0, byt.Length)
  cs.FlushFinalBlock()

  cs.Close()

  Return Encoding.UTF8.GetString(ms.ToArray())
End Function

// C#
private string DecryptString(string Value)
{
   ICryptoTransform ct;
   MemoryStream ms;
   CryptoStream cs;
   byte[] byt;

   ct = mCSP.CreateDecryptor(mCSP.Key, mCSP.IV);

   byt = Convert.FromBase64String(Value);

   ms = new MemoryStream();
   cs = new CryptoStream(ms, ct, CryptoStreamMode.Write);
   cs.Write(byt, 0, byt.Length);
   cs.FlushFinalBlock();

   cs.Close();

   return Encoding.UTF8.GetString(ms.ToArray());
}

There are only three differences between the Encrypt and the Decrypt functions.

  1. You will use the CreateDecryptor method of the CryptoServiceProvider class to create the appropriate ICtryptoTransform object.
  2. You will create a byte array from a Base64-encoded string. You will need to use the Convert.FromBase64String method to accomplish this.
  3. You create the appropriate memory stream from the array of bytes by applying the transform to the original byte array. You need to convert the memory stream from a byte array back into a normal string that you can display back on the form. You will use the Encoding.UTF8.GetString() method to perform this conversion.
    Note   The Encoding.UTF8 class comes from the System.Text namespace.

Can We Make It Simpler?!

OK, although the code presented so far is not hard, there are a lot of different classes and interfaces that you might not be used to working with. In addition, it is a lot of code to remember how to write off the top of your head. Let's learn how to wrap up the Cryptography classes into an easier to use class of our own.

There are two classes named PDSAHash and PDSAEncryption that are in an assembly named PDSACryptography. The purpose of these two classes is to encapsulate the actual mechanics of creating the hash string or encrypted string. In addition, they will allow you use an enumerated constant to make a decision on which hash or encryption algorithm you wish to use. Instead of having to remember all of the different names of each of the different cryptography service providers, you will get a nice Intellisense#&0174; list of providers.

PDSAHash wraps up hashing

The PDSAHash class contains the properties; HashType, HashObject, OriginalString, HashString, SaltValue, UseSalt and SaltLength. The methods associated with this class are SetEncryptor, CreateSalt, Reset, and CreateHash. There is an enumeration created in this class called PDSAHashType from which you may choose the appropriate hashing class to use. The goal of this class is to simplify the code presented earlier to the following code.

Private Sub UsePDSAHash()
  Dim ph As New PDSAHash(PDSAHash.PDSAHashType.MD5)

  MessageBox.Show(ph.CreateHash("Paul"))
End Sub

I would much rather type the above code than have to remember all of the code presented earlier. As you can see, this code is fairly straightforward and uses the same code you learned earlier, but just wraps it up into an easier-to-use interface. You can see the complete class in the sample included with this article. Below is the enumeration describing the different hash algorithms you can create using this class.

Public Enum PDSAHashType As Byte
  MD5
  SHA1
  SHA256
  SHA384
  SHA512
End Enum

Each one of these algorithms has varying degrees of security available for the final hash. The complete list of hash classes in .NET is as follows:

  • MD5CryptoServiceProvider
  • SHA1CryptoServiceProvider
  • SHA256Managed
  • SHA384Managed
  • SHA512Managed

Search the Visual Studio .NET online documentation for more information about each of these different hash types.

PDSAEncryption Wraps up Encryption

Just like the PDSAHash class wraps up all of the hashing functionality in the .NET Framework, the PDSAEncryption class wraps up all of the various Symmetric Algorithm classes in the .NET Framework. The PDSAEncryption class has the following enumerated types to allow you to create the various encryption/decryption objects.

Public Enum PDSAEncryptionType As Byte
  DES
  RC2
  Rijndael
  TripleDES
End Enum

Again, each of these various service providers gives you different degrees of security of the encrypted string. These are all very well documented in the online documentation within Visual Studio .NET, so I will not reiterate these here.

This class includes the properties; EncryptionType, OriginalString, EncryptedString, Key, KeyString, IV, IVString, and CryptoProvider. Most of these are self explanatory, but the Key and IV are byte arrays while KeyString and IVString are the string representations of these byte arrays.

There are a few methods in this class as well. For example, you have Encrypt and Decrypt. You also have GenerateKey and GenerateIV methods for creating a key and IV if you do not have one already. The SetEncryptor method is used to create the new CryptoProvider object that will be used in the various methods.

The goal of this class is to make it much easier to encrypt and decrypt strings. For example, the following code snippet shows how easy it is to encrypt a string with this class.

Private Sub btnHardCoded_Click( _
 ByVal sender As System.Object, _
 ByVal e As System.EventArgs) Handles btnHardCoded.Click
  Dim ps As New  PDSASymmetric( _ 
   PDSASymmetric.PDSAEncryptionType.TripleDES)

  MessageBox.Show(ps.Encrypt( _
   "Server=localhost;Database=Northwind;uid=sa;pwd=sa"))
End Sub

Summary

Keeping secrets using computers can be accomplished fairly easily using classes within the Microsoft .NET Framework. The Cryptography namespace has several classes that you will find do this job very neatly. Creating a wrapper around these classes will help you cut down the amount of code you need to write immensely. I would highly recommend you create a wrapper similar to the one shown in this article.

About the Author

Paul Sheriff is president of PDSA, Inc., which provides .NET consulting, products, and services, including an SDLC document and architectural framework (www.pdsa.com). Paul is Microsoft Regional Director for Southern California. His books on .NET include ASP.NET Developer's Jumpstart (Addison-Wesley) and several eBooks listed on the PDSA Web site.

Show:
© 2014 Microsoft