【问题标题】:RC4 Algorithm: Unable to Encrypt / Decrypt data where client uses Javascript and Server c#RC4 算法:无法加密/解密客户端使用 Javascript 和服务器 c# 的数据
【发布时间】:2012-10-25 18:55:53
【问题描述】:

我需要在 IIS (basicHttpBinding) 中托管的 .NET 4.0 WCF 应用程序和使用 JavaScript RC4 算法实现加密/解密数据的内部客户端应用程序系统之间传递加密(和 base64 编码)字符串数据。

到目前为止,我还没有成功地将客户端加密的数据发送到服务器,然后在服务器上对其进行解密(或相反——客户端解密从服务器响应接收到的数据)。我们已经尝试了互联网上 JavaScript 文件(以及 AES)中的一些 RC4 算法变体。

我已将客户端使用的 RC4 算法版本转换为 C#(JavaScript 文件位于:https://gist.github.com/2185197)。我创建了一个 html 页面,以纯客户端方式测试 JavaScript 加密/解密功能。这行得通。同样,通过单元测试,我已经确定 c# Encrypt / Decrypt 也适用于 .NET WCF 服务。通过这些测试,没有 base64 编码/解码。

使用 c# RC4 算法,我可以成功处理通过线路发送的数据的加密/解密,其中加密数据是 base64 编码并且客户端是 .NET 应用程序(使用与服务器相同的 C# 算法实现类)

我逐行检查了客户端 JavaScript (Firebug) 和 C# (Visual Studio) 算法,验证变量值是否匹配。一切都匹配,除了代码将整数值转换为字符串(通过字符)。这里的结果是不一致的。下面是问题所在。

下面是每个实现的代码行。

C#: var charX = Convert.ToChar(26).ToString();

JavaScript:

Var charX = String.fromCharCode(26);

一些视觉差异可能仅仅是由于 Firebug 和 Visual Studio 的渲染能力。 [我的理解是它们都应该呈现 UTF8 编码的字符串]。我读过 JavaScript 引擎和 JavaScript 语言的编码不同。因此,微软已经实施了一个修复 [https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/fromCharCode] 我试图实施但没有成功。我可能需要在 C# 代码中实现一些编码;但目前还没有确定

根据上述整数值 26 的示例,当检查变量值时,C# 代码会显示一个左箭头。 JavaScript 显示一个空格。对于 JavaScript,这与通过 W3Shools 完成的测试一致 (http://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_fromcharcode)

我是否需要在 .NET 应用程序中执行某种编码以确保字符处理在 JavaScript v C# 中是一致的?

提前致谢。

以下是 JavaScript 代码:

 function rc4(key, str) {
        var s = [], j = 0, x, res = '';
        for (var i = 0; i < 256; i++) {
            s[i] = i;
        }
        for (i = 0; i < 256; i++) {
            j = (j + s[i] + key.charCodeAt(i % key.length)) % 256;
            x = s[i];
            s[i] = s[j];
            s[j] = x;                
        }
        i = 0;
        j = 0;
        for (var y = 0; y < str.length; y++) {
            i = (i + 1) % 256;
            j = (j + s[i]) % 256;
            x = s[i];
            s[i] = s[j];
            s[j] = x;

            //res += String.fromCharCode(str.charCodeAt(y) ^ s[(s[i] + s[j]) % 256]);

            var sx = s[i] + s[j];
            var ssx =  s[sx % 256];
            var fromChar1 =str.charCodeAt(y);
            var fromChar2 = (fromChar1 ^ ssx);
            var fromChar3 = String.fromCharCode(fromChar2);  //******  PROBLEM LINE *******
            //var fromChar3 = fixedFromCharCode(fromChar2);                
            res += fromChar3;
        }
        return res;
    }

    //Fix as per Microsoft
    //https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/fromCharCode
     function fixedFromCharCode(codePt) {
        if (codePt > 0xFFFF) {
            codePt -= 0x10000;
            return String.fromCharCode(0xD800 + (codePt >> 10), 0xDC00 + (codePt & 0x3FF));
        }
        else {
            return String.fromCharCode(codePt);
        }
    }

下面是c#代码:

public class RC4
{
    public static string Encrypt(string key, string data)
    {
        var s = new List<int>();
        var j = 0;

        var x = 0;
        var res = string.Empty;

        for (var i = 0; i < 256; i++)
        {
            s.Add(i);
        }

        for (var i = 0; i < 256; i++)
        {
            var unicodeInt01 = ConvertedCharacterToItsUnicodeNumberic(key, i);

            j = (j + s[i] + unicodeInt01) % 256;

            x = s[i];
            s[i] = s[j];
            s[j] = x;
        }

        var f = 0;
        j = 0;
        for (var y = 0; y < data.Length; y++)
        {
            f = (f + 1) % 256;
            j = (j + s[f]) % 256;
            x = s[f];
            s[f] = s[j];
            s[j] = x;

            var unicodInt02 = ConvertedCharacterToItsUnicodeNumberic(data, y);
            var convStringOperationApplied = unicodInt02 ^ s[(s[f] + s[j]) % 256];

            var charX = Convert.ToChar(convStringOperationApplied);   //******  PROBLEM LINE *******
            var val = new string(charX, 1);
            res += val;

        }

        return res;
    }

    private static int ConvertedCharacterToItsUnicodeNumberic(string key, int i)
    {
        return key.ElementAt(i % key.Length);
    }

    public static string Decrypt(string key, string data)
    {
        return Encrypt(key, data);
    }
}

【问题讨论】:

  • 为什么选择 RC4?只能使用一次密钥非常烦人。
  • 嗨。我们正在开发一个已经使用 RC4 的遗留系统。可能可以更改为更新和更强大的算法,但没有成功(如 RC4 等开放选项的基础),我们不愿意进行更改。已经使用 AES 进行了测试,但同样的问题。
  • RC4 的问题在于 1) 如果你重用一个密钥,解密这些消息变得很容易 2) RC4 的相关密钥弱点阻止你简单地连接密钥和随机数来形成实际的 RC4 密钥.所以它很容易以非常弱的方式使用。
  • 感谢您的指点。而且,是的,我完全同意。该系统至少是内部的;并且键有所不同。肯定想为更强的算法做,但 RC4 在这种情况下必须做。
  • 有人可能想知道为什么我们有这么多安全故障,这里有一个正在进行的示例。 OP 声明他们可以更改为安全加密算法 (AES),但选择不更改。事情就是这样发生的。

标签: c# javascript encryption rc4-cipher


【解决方案1】:

我认为您只需要对发送到代码的值进行 URL 编码。我在没有任何更改的情况下运行它,并注意到 FF 和 IE 发送了两个不同的值。所以我在发送值之前使用了 encodeURICompontent ,它工作得很好。 RC4 算法没有变化

<script>
    $(function () {
        var value = encodeURIComponent(rc4('9F32B12B2D34FD5FB6B9F372DE67D5C38FC8BF862DB3486C52E5211589B50AB0', 'Welcome to ASP.NET MVC!'));
        $('#encrypted').val(value);
        $.get('/Home/Test?value=' + value, function (d) {
            $('#decrypted').val(d);
        });
    });
</script>
<textarea id="encrypted">
</textarea>

<textarea id="decrypted">
</textarea>

这是我在服务器端(ASP.NET MVC)所拥有的:

public string Test(string value)
{
    string test = RC4.Decrypt("9F32B12B2D34FD5FB6B9F372DE67D5C38FC8BF862DB3486C52E5211589B50AB0", value);

    return test;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-29
    • 1970-01-01
    • 2015-10-29
    • 2021-09-22
    • 1970-01-01
    • 2020-09-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多