我在使用银行的网络服务传递信用卡付款时遇到了一些问题。他们需要对出站数据进行 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;
}
}