1

我在使用银行的网络服务传递信用卡付款时遇到了一些问题。他们需要对出站数据进行 RC4 加密,他们希望这些数据采用十六进制格式。

这是他们给我使用的测试网站:http ://www.fyneworks.com/encryption/rc4-encryption/index.asp

当我拿一张样本卡,并传入上面表格生成的值时,它们是正确的,并且这张卡被接受了。当我使用下面的 frankencode(从我在互联网上找到的片段拼凑而成)时,十六进制值不正确,并且每次都拒绝卡。在某些情况下,encName 完全关闭。在 encCCNum 和 encCVVTest 的情况下,它大约是正确的一半。在 encExpyMonth 和 encExpyYear 的情况下,它完全正确。

我确定问题出在我的算法中,甚至可能是十六进制转换,但我在密码学编程方面真的没有太多经验,所以我什至不知道从哪里开始调试。有人可以帮帮我吗?这是 C#.net 中的一个 Web 应用程序,顺便说一句。

 rc4encrypt rc4 = new rc4encrypt();
 rc4.Password = "B83E13EC";
 rc4.PlainText = sNameTest;
 encName = rc4.EnDeCrypt();
 rc4.Password = "B83E13EC";
 rc4.PlainText = sCCNumTest;
 encCCNum = rc4.EnDeCrypt();
 rc4.Password = "B83E13EC";
 rc4.PlainText = sExpyMonthTest;
 encExpyMonth = rc4.EnDeCrypt();
 rc4.Password = "B83E13EC";
 rc4.PlainText = sExpyYearTest;
 encExpyYear = rc4.EnDeCrypt();
 rc4.Password = "B83E13EC";
 rc4.PlainText = sCVVTest;
 encCVVTest = rc4.EnDeCrypt();

   public class rc4encrypt
    {
        protected int[] sbox = new int[256];
        protected int[] key = new int[256];

        protected string plaintext, password;

        public string PlainText
        {
            set { plaintext = value; }
            get { return plaintext; }
        }

        public string Password
        {
            set { password = value; }
            get { return password; }
        }

        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;
            }

            // 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;
            }
        }

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

            // 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

            //Convert to hexadecimal - added by BN
            string finalcipher = string.Empty;
            char[] values = cipher.ToCharArray();
            foreach (char letter in values)
            {
                // Get the integral value of the character. 
                int value = Convert.ToInt32(letter);
                // Convert the decimal value to a hexadecimal value in string form. 
                finalcipher += String.Format("{0:X}", value);

            }

            return finalcipher;
        }

    }
4

1 回答 1

4

不要扮演你自己的加密代码。它通常是错误的。Bouncy castle有一个支持 RC4 的 C# 实现。为什么不使用它?

于 2013-03-22T22:31:26.283 回答