Алгоритм RC4: невозможно зашифровать / расшифровать данные, когда клиент использует Javascript и сервер C#
Мне нужно передать зашифрованные (и закодированные в base64) строковые данные между приложением WCF.NET 4.0, размещенным в IIS (basicHttpBinding), и внутренней системой клиентских приложений, которая использует реализацию алгоритма JavaScript RC4 для шифрования / дешифрования данных.
До сих пор мне не удалось отправить данные, зашифрованные клиентом, на сервер, а затем расшифровать их на сервере (или наоборот - там, где клиент расшифровывает данные, полученные из ответа сервера). Мы попробовали несколько вариантов алгоритмов RC4, найденных в файлах JavaScript в Интернете (а также AES).
Я преобразовал версию алгоритма 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), проверяя соответствие значений переменных. Все совпадает, за исключением случаев, когда код преобразует целочисленное значение в String (через Char). Результат здесь противоречивый. Ниже указана проблемная линия.
Ниже приведена строка кода для каждой реализации.
C#: var charX = Convert.ToChar (26).ToString ();
JavaScript:
Var charX = String.fromCharCode (26);
Некоторые визуальные различия могут быть просто связаны с возможностями рендеринга Firebug и Visual Studio. [Насколько я понимаю, они оба должны воспроизводить строки в кодировке UTF8]. Я читал, что движок JavaScript и язык 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 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);
}
}
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;
}