这个C#中的RC4加密代码有什么问题吗

发布于 2024-12-01 18:09:20 字数 3146 浏览 1 评论 0 原文

我正在尝试收听 Foxycart XML Datafeed 在 C# 中,遇到了一个归结为加密的问题。

简而言之,他们使用 RC4 加密 将数据作为编码和加密的 XML 发送。

为了进行测试,他们有一些(用户提交的)示例代码来使用 C# 进行测试。我尝试使用其中一位用户提供的示例 RC4 解密代码,但它似乎不起作用,并且他们的支持人员认为它与 C# RC4 算法有关。由于他们不是 C# 专家,我想我应该在这里问。这是 FoxyCart 论坛上的帖子

无论如何,这里是通过加密 XML 文件并将其发布到 URL 来(尝试)模拟响应的代码(请注意,DataFeedKey 是我存储为成员变量的字符串):

public ActionResult TestDataFeed()
{
    string transactionData = (new StreamReader(@"D:\SampleFeed.xml")).ReadToEnd();
    string encryptedTransactionData = RC4.Encrypt(DataFeedKey, transactionData, false);
    string encodedTransactionData = HttpUtility.UrlEncode(encryptedTransactionData,     Encoding.GetEncoding(1252));
    string postData = "FoxyData=" + encodedTransactionData;
    var req = (HttpWebRequest)WebRequest.Create("http://localhost:3396/FoxyCart/RecieveDataFeed");
    req.Method = "POST";
    req.ContentType = "application/x-www-form-urlencoded";
    var sw = new StreamWriter(req.GetRequestStream(), Encoding.ASCII);
    sw.Write(postData);
    sw.Close();
    HttpWebResponse resp = null;
    try
    {
        resp = (HttpWebResponse)req.GetResponse();
        string r = new StreamReader(resp.GetResponseStream()).ReadToEnd();
    }
    catch (WebException ex)
    {
        string err = new StreamReader(ex.Response.GetResponseStream()).ReadToEnd();
    }
    return null;
}

这是回调接收响应的方法。

[ValidateInput(false)]
public ActionResult RecieveDataFeed(FormCollection collection)
{
    string unencodedFeed = HttpUtility.UrlDecode(collection["FoxyData"],     Encoding.GetEncoding(1252));
    string transaction = RC4.Decrypt(DataFeedKey, unencodedFeed, false);
    return Content("foxy");
}

这里是此 RC4 类代码的链接,而不是在此问题中内联发布整个 RC4 类

正如我在问题顶部的上述链接中发布的那样,问题是当我检查

 RecieveDataFeed()

方法内的变量事务时,我应该返回常规 XML,但我看到的是:

É?xø´ v´“Û·8êUŸí¥MïSÅJÖó5Cå7ã…ÄlÞ&þòG·¶ÝÙ3<ÍÖ¡«úüF¿¿ßìNµ>4¦Äu÷¼Â;£-w¤ƒûÊyL¹®½èíYö½’é(µJŒ~»»=3¼]F‡•=±Ùí]'鳫"øPç{Ù^yyéå–°ñ…5ðWF$zÉnÄ^_”Xë’ï%œ-5á
ÒÛ€jŠt`Â9œÇÞLU&¼~ç2îžúo/¢¶5,º*öOqÝ—‘.ó®šuf™å5G—õC®‰ÁéiÇúW®¦ÝÚ•Z±:„Q\p"p
ôÔiÛ!\D"ÉÂX3]ƒ°è€Œ«DQE‡kÝ@àö`gpöŽ÷nÛ={µÏßKQKüå(ö%¯¯Ü–9}¨¬°£7yo,«”ÜëCÍ/+…†ÕËî‘‹‰AÚmÇÙå©&©¡xÙkŒföX¯ÃX&×°S|kÜ6Ô°Üú\Ätóü-äUƆÈáÅ\ ’E8‚¤âÈ4Ž¾«ãΚ_Sï£y‰xJº•bm*jo›‰ÜW–[ô†ÆJÐà$½…9½šžˆ_ÙÜù/®öÁVhzŠ¥ú(ñ£²6ˆb6¢ëße¤oáIðZuK}ÆÙ]"T¼*åZêñß5K—½òQSåRN Çë'Å¡
ÕyiÈX •bØðIk¿WxwNàäx®‹?cv+X™¥E!gd4â¤nÔ‹¢½Ð”ªÊ­Q!‚.e8s
Gyª4¼ò,}Yœ‚¹”±E‡Jy}Sæ
ƒ¦ýK'Ð}~B¦E3!0°ú´A–5Þ³£9$–8äÏ©?
 œ‡8GÂø

代码看起来正确:

  1. Encrypt
  2. Encode
  3. Decode
  4. Decrypt

但是它似乎不起作用。对于上面可能出现的问题有什么建议吗?

I am trying to listen to the Foxycart XML Datafeed in C# and running into an issue which boils down to encryption.

In short, they send over their data as encoded and encrypted XML using RC4 encryption.

To test, they have some (user submitted) sample code to test this with C#. I tried using this sample RC4 decryption code provided by one of the users but it doesn't seem to work and their support staff thinks its down with the C# RC4 algorithm. Since they are not C# experts, i figured i would ask here. Here is the post on the FoxyCart forum

Anyway, here is the code that (tries to) simulate the response by encrypting an XML file and posting it to a URL (NOTE that DataFeedKey is a string that i have stored as a member variable):

public ActionResult TestDataFeed()
{
    string transactionData = (new StreamReader(@"D:\SampleFeed.xml")).ReadToEnd();
    string encryptedTransactionData = RC4.Encrypt(DataFeedKey, transactionData, false);
    string encodedTransactionData = HttpUtility.UrlEncode(encryptedTransactionData,     Encoding.GetEncoding(1252));
    string postData = "FoxyData=" + encodedTransactionData;
    var req = (HttpWebRequest)WebRequest.Create("http://localhost:3396/FoxyCart/RecieveDataFeed");
    req.Method = "POST";
    req.ContentType = "application/x-www-form-urlencoded";
    var sw = new StreamWriter(req.GetRequestStream(), Encoding.ASCII);
    sw.Write(postData);
    sw.Close();
    HttpWebResponse resp = null;
    try
    {
        resp = (HttpWebResponse)req.GetResponse();
        string r = new StreamReader(resp.GetResponseStream()).ReadToEnd();
    }
    catch (WebException ex)
    {
        string err = new StreamReader(ex.Response.GetResponseStream()).ReadToEnd();
    }
    return null;
}

and here is the callback method that receives the response.

[ValidateInput(false)]
public ActionResult RecieveDataFeed(FormCollection collection)
{
    string unencodedFeed = HttpUtility.UrlDecode(collection["FoxyData"],     Encoding.GetEncoding(1252));
    string transaction = RC4.Decrypt(DataFeedKey, unencodedFeed, false);
    return Content("foxy");
}

Instead of posting the whole RC4 class inline in this question, here is a link to the code of this RC4 class.

As i posted in the above link at the top of the question, the issue is when i check the variable transaction inside the

 RecieveDataFeed()

method, i should have the regular XML back but instead i see this:

É?xø´ v´“Û·8êUŸí¥MïSÅJÖó5Cå7ã…ÄlÞ&þòG·¶ÝÙ3<ÍÖ¡«úüF¿¿ßìNµ>4¦Äu÷¼Â;£-w¤ƒûÊyL¹®½èíYö½’é(µJŒ~»»=3¼]F‡•=±Ùí]'鳫"øPç{Ù^yyéå–°ñ…5ðWF$zÉnÄ^_”Xë’ï%œ-5á
ÒÛ€jŠt`Â9œÇÞLU&¼~ç2îžúo/¢¶5,º*öOqÝ—‘.ó®šuf™å5G—õC®‰ÁéiÇúW®¦ÝÚ•Z±:„Q\p"p
ôÔiÛ!\D"ÉÂX3]ƒ°è€Œ«DQE‡kÝ@àö`gpöŽ÷nÛ={µÏßKQKüå(ö%¯¯Ü–9}¨¬°£7yo,«”ÜëCÍ/+…†ÕËî‘‹‰AÚmÇÙå©&©¡xÙkŒföX¯ÃX&×°S|kÜ6Ô°Üú\Ätóü-äUƆÈáÅ\ ’E8‚¤âÈ4Ž¾«ãΚ_Sï£y‰xJº•bm*jo›‰ÜW–[ô†ÆJÐà$½…9½šžˆ_ÙÜù/®öÁVhzŠ¥ú(ñ£²6ˆb6¢ëße¤oáIðZuK}ÆÙ]"T¼*åZêñß5K—½òQSåRN Çë'Å¡
ÕyiÈX •bØðIk¿WxwNàäx®‹?cv+X™¥E!gd4â¤nÔ‹¢½Ð”ªÊ­Q!‚.e8s
Gyª4¼ò,}Yœ‚¹”±E‡Jy}Sæ
ƒ¦ýK'Ð}~B¦E3!0°ú´A–5Þ³£9$–8äÏ©?
 œ‡8GÂø

The code looks right:

  1. Encrypt
  2. Encode
  3. Decode
  4. Decrypt

but it doesn't seem to be working. Any suggestions on what might be wrong above?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦忆晨望 2024-12-08 18:09:20

CR4 类中的代码让我有点惊讶。我看不出它如何可靠地工作。

该代码使用 windows-1252 编码将字符编码为字节,然后加密字节并尝试将字节解码为字符。这不会可靠地工作,因为您只能解码来自编码字符的字节。

该方法接受一个字符串并返回一个字符串,但它应该接受一个字节数组并返回一个字节数组,类似于框架中所有加密类的做法。

这是一个类似的版本:

public class RC4 {

  public static byte[] Encrypt(byte[] pwd, byte[] data) {
    int a, i, j, k, tmp;
    int[] key, box;
    byte[] cipher;

    key = new int[256];
    box = new int[256];
    cipher = new byte[data.Length];

    for (i = 0; i < 256; i++) {
      key[i] = pwd[i % pwd.Length];
      box[i] = i;
    }
    for (j = i = 0; i < 256; i++) {
      j = (j + box[i] + key[i]) % 256;
      tmp = box[i];
      box[i] = box[j];
      box[j] = tmp;
    }
    for (a = j = i = 0; i < data.Length; i++) {
      a++;
      a %= 256;
      j += box[a];
      j %= 256;
      tmp = box[a];
      box[a] = box[j];
      box[j] = tmp;
      k = box[((box[a] + box[j]) % 256)];
      cipher[i] = (byte)(data[i] ^ k);
    }
    return cipher;
  }

  public static byte[] Decrypt(byte[] pwd, byte[] data) {
    return Encrypt(pwd, data);
  }

}

示例:

string data = "This is a test.";
byte[] key = { 1, 2, 3, 4, 5 };

// encrypt
byte[] enc = RC4.Encrypt(key, Encoding.UTF8.GetBytes(data));

// turn into base64 for convenient transport as form data
string base64 = Convert.ToBase64String(enc);

Console.WriteLine(base64);

// turn back into byte array
byte[] code = Convert.FromBase64String(base64);

// decrypt
string dec = Encoding.UTF8.GetString(RC4.Decrypt(key, code));

Console.WriteLine(dec);

输出:

5lEKdtBUswet4yYveWU2
This is a test.

I am a bit surprised by the code in the CR4 class. I can't see how it would work reliably.

The code uses windows-1252 encoding to encode characters into bytes, then it encrypts the bytes and tries to decode the bytes into characters. That won't work reliably, as you can only decode bytes that comes from encoding characters.

The method takes a string and returns a string, but it should take a byte array and return a byte array, similar to how all the encryption classes in the framework does it.

Here is a version that works like that:

public class RC4 {

  public static byte[] Encrypt(byte[] pwd, byte[] data) {
    int a, i, j, k, tmp;
    int[] key, box;
    byte[] cipher;

    key = new int[256];
    box = new int[256];
    cipher = new byte[data.Length];

    for (i = 0; i < 256; i++) {
      key[i] = pwd[i % pwd.Length];
      box[i] = i;
    }
    for (j = i = 0; i < 256; i++) {
      j = (j + box[i] + key[i]) % 256;
      tmp = box[i];
      box[i] = box[j];
      box[j] = tmp;
    }
    for (a = j = i = 0; i < data.Length; i++) {
      a++;
      a %= 256;
      j += box[a];
      j %= 256;
      tmp = box[a];
      box[a] = box[j];
      box[j] = tmp;
      k = box[((box[a] + box[j]) % 256)];
      cipher[i] = (byte)(data[i] ^ k);
    }
    return cipher;
  }

  public static byte[] Decrypt(byte[] pwd, byte[] data) {
    return Encrypt(pwd, data);
  }

}

Example:

string data = "This is a test.";
byte[] key = { 1, 2, 3, 4, 5 };

// encrypt
byte[] enc = RC4.Encrypt(key, Encoding.UTF8.GetBytes(data));

// turn into base64 for convenient transport as form data
string base64 = Convert.ToBase64String(enc);

Console.WriteLine(base64);

// turn back into byte array
byte[] code = Convert.FromBase64String(base64);

// decrypt
string dec = Encoding.UTF8.GetString(RC4.Decrypt(key, code));

Console.WriteLine(dec);

Output:

5lEKdtBUswet4yYveWU2
This is a test.
暗喜 2024-12-08 18:09:20

虽然这更像是在黑暗中拍摄......我相当确定实现 RC4 的类看起来像是假设一切都是 ASCII 或 CodePage 1252 - 两者都是错误的,因为我假设提供的 XML 是 UTF-8 和 .NET内存中的字符串表示是 UTF16...

如果我的假设是正确的,那么当您从加密中取回数据时,数据已经被扰乱了...

编辑 - C# 中工作 RC4 代码的一些链接:

Although this is more shooting in the dark... I am rather certain that the class implementing RC4 looks like it is assuming everyting is either ASCII or CodePage 1252 - both is wrong because I assume that the XML supplied is UTF-8 and .NET string represantion in memory is UTF16...

If my assumption is right the data is already scrambled when you get it back from encryption...

EDIT - some links to working RC4 code in C#:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文