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


  • Read Part 1
    Read Part 2

  • 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() + "<br>");
        Response.Write(cs.ToString() + "<br>");
        Response.Write(vb.ToString() + "<br>");
        Response.Write(cs.Equals(vb).ToString() + "<br><br>");
    }
    

    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());
    
    [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.

    If you have any questions or feedback, please contact me at chris@hostorlando.com.

    Happy Programming!

  • By Chris Scott

  • Article Information
    Article Title: ASP.NET.Converting Mike Shaffer's VBScript RC4 Encryption Code to C#, Part 3
    Article Author: Chris Scott
    Published Date: September 18, 2002
    Article URL: http://www.4GuysFromRolla.com/articles/091802-1.3.aspx


    Copyright 2017 QuinStreet Inc. All Rights Reserved.
    Legal Notices, Licensing, Permissions, Privacy Policy.
    Advertise | Newsletters | E-mail Offers