To read the article online, visit http://www.4GuysFromRolla.com/articles/091802-1.3.aspx

# Converting Mike Shaffer's VBScript RC4 Encryption Code to C#, Part 3

By Chris Scott

• In Part 2 we started the conversion of Mike's code from VBScript to C#. Specifically, we had examined three hurdles involved in the conversion process. In this final part we'll look at the remaining hurdles and examine the `rc4encyrpt` class in use!

Hurdle #4: C# doesn't have the VBScript functions `Mid()` and `Asc()`. In the code below, you'll see how we work around those problems.

Here's the C# version with comments (prefixed with //):

 ``` private void RC4Initialize(string strPwd) { // Get the length of the password // Instead of Len(), we need to use the Length property // of the string int intLength = strPwd.Length; // Set up our for loop. In C#, we need to change our syntax. // The first argument is the initializer. Here we declare a // as an integer and set it equal to zero. // The second argument is expression that is used to test // for the loop termination. Since our arrays have 256 // elements and are always zero based, we need to loop as long // as a is less than or equal to 255. // The third argument is an iterator used to increment the // value of a by one each time through the loop. Note that // we can use the ++ increment notation instead of a = a + 1 for (int a = 0; a <= 255; a++) { // Since we don't have Mid() in C#, we use the C# // equivalent of Mid(), String.Substring, to get a // single character from strPwd. We declare a character // variable, ctmp, to hold this value. // A couple things to note. First, the Mod keyword we // used in VB need to be replaced with the % // operator C# uses. Next, since the return type of // String.Substring is a string, we need to convert it to // a char using String.ToCharArray() and specifying that // we want the first value in the array, [0]. char ctmp = (strPwd.Substring((a % intLength),1).ToCharArray()[0]); // We now have our character and need to get the ASCII // code for it. C# doesn't have the VB Asc(), but that // doesn't mean we can't use it. In the beginning of our // code, we imported the Microsoft.VisualBasic namespace. // This allows us to use many of the native VB functions // in C# // Note that we need to use [] instead of () for our // array members. key[a] = Microsoft.VisualBasic.Strings.Asc(ctmp); sbox[a] = a; } ... } ```

Some of you may wonder why I didn't just cast the ASCII character code to a `char` in C# instead of using `Chr()` from the `VisualBasic` namespace (as well as casting the `char` to an `int` instead of using `Asc()`). As an example, take casting an `int` to a `char`:

 ``` int i = 65; char tmp = (char) i; Response.Write(tmp.ToString()); ```

This bit of code works and returns the same as the VB function `Chr(65)`: a capital letter "A". The problem is when the character code (i, in the code above) is greater than 128. This is the point where the results from both methods are not the same. As a test, you can use the following code to write out the integer value, the character value when the `int` is casted as a `char`, and the character value when the `Chr()` function is used:

 ```for (int i = 0; i <= 255; i++) { char cs = (char) i; char vb = Microsoft.VisualBasic.Strings.Chr(i); Response.Write(i.ToString() + "
"); Response.Write(cs.ToString() + "
"); Response.Write(vb.ToString() + "
"); Response.Write(cs.Equals(vb).ToString() + "

"); } ```

Due to this, it became clear that it was much easier to use the VB functions provided by the `VisualBasic` namespace.

The remaining VBScript code in the `RC4Initialize` sub is as follows:

 ``` b = 0 For a = 0 To 255 b = (b + sbox(a) + key(a)) Mod 256 tempSwap = sbox(a) sbox(a) = sbox(b) sbox(b) = tempSwap Next ```

Here's the C# version with comments:

 ``` private void RC4Initialize(string strPwd) { ... // Declare an integer x and initialize it to zero. int x = 0; // Again, create a for loop like the one above. Note that we // need to use a different variable since we've already // declared a above. for (int b = 0; b <= 255; b++) { x = (x + sbox[b] + key[b]) % 256; int tempSwap = sbox[b]; sbox[b] = sbox[x]; sbox[x] = tempSwap; } } ```

See, that wasn't too bad. All that remains now is to convert the VBScript `EnDeCrypt` function to a method in our `rc4encrypt` class. This time, we need to declare it as a `public` method so that our external source code can call the method. If we marked the method as `private`, as we did with the `RC4Initialize` method, the `EnDeCrypt` method would only be available to methods within our `rc4encrypt` class. Also, we need to have the `EnDeCrypt` method return a string value.

 ``` public string EnDeCrypt() { // TODO: Code for EnDeCrypt goes here... } ```

Note that unlike the `EnDeCrypt` function in the VBScript version, the C# version doesn't take any input parameters. Since we already have class-level properties for `Password` and `PlainText`, we can make use of these properties instead of passing them in as input parameters in the call to `EnDeCrypt`. This isn't a requirement, as we could have omitted the properties and created the `EnDeCrypt` method to accept two string input parameters.

In the `EnDeCrypt` method, the first thing we need to do is to declare some variables that will be used by this method:

 ``` public string EnDeCrypt() { int i = 0; int j = 0; string cipher = ""; ... } ```

An important thing to note about the above code is that the string cipher is initialized to an empty string. This is necessary since in the code that follows we will use that variable to append values to and then return as the value of the EnDeCrypt method. This is important because if you don't, you'll get a runtime error (the compiler won't complain) about trying to use an uninitialized value.

We're now left with converting the following VBScript code:

 ``` RC4Initialize psw For a = 1 To Len(plaintxt) i = (i + 1) Mod 256 j = (j + sbox(i)) Mod 256 temp = sbox(i) sbox(i) = sbox(j) sbox(j) = temp k = sbox((sbox(i) + sbox(j)) Mod 256) cipherby = Asc(Mid(plaintxt, a, 1)) Xor k cipher = cipher & Chr(cipherby) Next EnDeCrypt = cipher ```

We've already overcome the hurdle of not having the `Asc()` and `Mid()` functions available, but what about that `Chr()` function?

Hurdle #5: C# does not have a `Chr()` function. However, you'll see below how we use the `Microsoft.VisualBasic` namespace again.

Here's the C# version with comments:

 ``` public string EnDeCrypt() { ... // Call our method to initialize the arrays used here. RC4Initialize(password); // Set up a for loop. Again, we use the Length property // of our String instead of the Len() function for (int a = 1; a <= plaintext.Length; a++) { // Initialize an integer variable we will use in this loop int itmp = 0; // Like the RC4Initialize method, we need to use the % // in place of Mod i = (i + 1) % 256; j = (j + sbox[i]) % 256; itmp = sbox[i]; sbox[i] = sbox[j]; sbox[j] = itmp; int k = sbox[(sbox[i] + sbox[j]) % 256]; // Again, since the return type of String.Substring is a // string, we need to convert it to a char using // String.ToCharArray() and specifying that we want the // first value, [0]. char ctmp = plaintext.Substring(a - 1, 1).ToCharArray() [0]; // Use Asc() from the Microsoft.VisualBasic namespace itmp = Microsoft.VisualBasic.Strings.Asc(ctmp); // Here we need to use ^ operator that C# uses for Xor int cipherby = itmp ^ k; // Use Chr() from the Microsoft.VisualBasic namespace cipher += Microsoft.VisualBasic.Strings.Chr(cipherby); } // Return the value of cipher as the return value of our // method return cipher; } ```

So, there you have it, a complete conversion from VBScript to C#. Be sure to view the complete source code.

## Using the `rc4encrypt` Class

At this point you may be wondering how to use the `rc4encrypt` class in your C# app (or ASP.NET Web page). First things first - make sure you have compiled the class into a DLL. If you are using VS.NET you can simply go to the Build menu and select the Build Solution option. If you are not using VS.NET you'll need to use the command-line compiler. Navigate to the directory where your `.cs` file resides and type in:
`csc /t:library /r:Microsoft.VisualBasic.dll FileName.cs`

Where `FileName.cs` is the name of the class file you created that contains the source code presented above.

Once you have the class in DLL-form, to use it simply instantiate the object, set the `PlainText` and `Password` properties and then call the `EnDeCrypt()` method. (Note that to use it in an ASP.NET Web page the compiled DLL will need to be placed in your Web application's `/bin` directory).

Here's a quick code sample with comments:

 ```// Instantiate our object. main.rc4encrypt is the namespace // name and the class name which gives us a reference to the // class. We use rc4 as the variable name for our object and // use the new keyword to create a new instance of the object main.rc4encrypt rc4 = new main.rc4encrypt(); // Set the Password property to the password we want to use rc4.Password = "secretsquirrel"; // Set the PlainText password of the text we want to encrypt rc4.PlainText = "testing123"; // Write out to the page the encrypted output Response.Write(rc4.EnDeCrypt() + "
"); // Set the PlainText property to the encrypted output // Note that we don't have to reinstantiate the object but // instead reuse it. rc4.PlainText = rc4.EnDeCrypt() ; // Write out to the page the decrypted output Response.Write(rc4.EnDeCrypt()); ```
[View a Live Demo!]

If everything worked, you should see the encrypted output and on the next line the decrypted output which is equal to "testing123". The live demo allows you to provide your own password and plain text strings.