Алгоритм RC4: невозможно зашифровать/расшифровать данные, если клиент использует Javascript и сервер c#

Мне нужно передать зашифрованные (и закодированные в base64) строковые данные между приложением .NET 4.0 WCF, размещенным в IIS (basicHttpBinding), и внутренней системой клиентских приложений, которая использует реализацию алгоритма JavaScript RC4 для шифрования/дешифрования данных.

Пока мне не удалось отправить данные, зашифрованные клиентом, на сервер, а затем расшифровать их на сервере (или наоборот — когда клиент расшифровывает данные, полученные из ответа сервера). Мы попробовали несколько вариантов алгоритмов RC4, найденных в файлах JavaScript в Интернете (а также AES).

Я преобразовал версию алгоритма RC4, которую использует клиент, в C# (файл JavaScript, расположенный по адресу: https://gist.github.com/2185197). Я создал html-страницу, чтобы протестировать функциональность шифрования/дешифрования JavaScript исключительно на стороне клиента. Это работает. Точно так же с помощью модульного тестирования я установил, что c# Encrypt/Decrypt также работает в службе .NET WCF. С этими тестами не было кодирования/декодирования base64.

Используя алгоритм С# RC4, я могу успешно обрабатывать шифрование/дешифрование данных, отправляемых по сети, где зашифрованные данные закодированы в base64 И где клиент является приложением .NET (используя тот же класс реализации алгоритма С#, что и сервер)

Я шаг за шагом прошел через клиентский алгоритм JavaScript (Firebug) и C# (Visual Studio), проверяя, совпадают ли значения переменных. Все совпадает, за исключением того, где код преобразует целочисленное значение в строку (через Char). Результат здесь неоднозначный. Ниже находится проблемная строка.

Ниже приведена строка кода для каждой реализации.

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

JavaScript:

Var charX = String.fromCharCode(26);

Некоторые визуальные различия могут быть просто связаны с возможностями рендеринга Firebug и Visual Studio. [Насколько я понимаю, они оба должны отображать строки в кодировке UTF8]. Я читал, что JavaScript Engine и язык JavaScript различаются по своей кодировке. Таким образом, Microsoft внедрила исправление [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 и 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);
        }
    }

Ниже приведен код С#:

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

person Grant Sutcliffe    schedule 25.10.2012    source источник
comment
Почему RC4? Возможность использовать ключ только один раз довольно раздражает.   -  person CodesInChaos    schedule 26.10.2012
comment
Привет. Мы работаем над устаревшей системой, уже использующей RC4. Возможно, можно было бы внести изменения в более новый и более сильный алгоритм, но, не преуспев в основах (таких открытых вариантов, как RC4), мы не хотим вносить изменения. Уже протестировано с использованием AES, но те же проблемы.   -  person Grant Sutcliffe    schedule 07.11.2012
comment
Проблема с RC4 заключается в том, что 1) Если вы повторно используете ключ, становится легко расшифровать эти сообщения. 2) Связанные с этим недостатки ключа RC4 не позволяют вам просто конкатенировать ключ и одноразовый номер для формирования фактического ключа RC4. Так что это очень легко использовать таким образом, что это очень слабо.   -  person CodesInChaos    schedule 07.11.2012
comment
Спасибо за указатели. И да, я полностью согласен. Система как минимум внутренняя; и ключи разные. Определенно хотелось бы сделать более сильный алгоритм, но в этой ситуации придется использовать RC4.   -  person Grant Sutcliffe    schedule 08.11.2012
comment
Можно задаться вопросом, почему у нас так много сбоев в системе безопасности, вот пример одного из них. В ОП говорится, что они могут перейти на безопасный алгоритм шифрования (AES), но предпочитают этого не делать. Вот как это происходит.   -  person zaph    schedule 17.12.2015


Ответы (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;
}
person nerdybeardo    schedule 25.10.2012