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:
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() + "<br>");
// 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());
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.