Строки XOR: JS против PHP - PullRequest
       49

Строки XOR: JS против PHP

4 голосов
/ 15 октября 2019

Я попытался выполнить XOR для двух строк в PHP и в JS, и я получил разные результаты:

PHP-функция

function xh($a, $b) {
  $res = ""; $i = strlen($a); $j = strlen($b);
  while($i-->0 && $j-->0) {
    $res.= $a[$i] ^ $b[$j];
  }
  return base64_encode($res);
}

JS-функция

function xh(a, b) {
  var res = "", i = a.length, j = b.length;
  while (i-->0 && j-->0) {
    res+= String.fromCharCode(a.charCodeAt(i) ^ b.charCodeAt(j));
  }
  return btoa(res);
}

Я проверил байты и обнаружил, что шестой байт в функции PHP всегда равен нулю, поэтому я обновил функцию JS до

Функция JS эквивалентна PHP

function xh2(a, b) {
  var res = "", i = a.length, j = b.length;
  while (i-->0 && j-->0) {
    res+= String.fromCharCode((a.charCodeAt(i) ^ b.charCodeAt(j)) & 95);
  }
  return btoa(res);
}

Так что же происходит с этим битом?

Пример ввода / вывода:

string a: 5D41402ABC4B2A76B9719D911017C592
string b: FE2D010308A6B3799A3D9C728EE74244
PHP says: Bg0HVwBUVQkDDgcAVQRYWw8AUlBUVVtSUgIBBFUGAVM=
 JS says: Bg0HdwB0dQkDDgcAdQR4ew8AcnB0dXtycgIBBHUGAXM=
JS2 says: Bg0HVwBUVQkDDgcAVQRYWw8AUlBUVVtSUgIBBFUGAVM=

Первое отличие в этом примере:

C: 0x43  = 0100 0011
4: 0x34  = 0011 0100
C^4 (JS) = 0111 0111 = 0x77 (correct)
C^4 (PHP)= 0101 0111 = 0x57
             ^
             sixth bit wrong

Входными данными являются хэши MD5, я использую кодировку по умолчанию, моя кодировка OEM - CP1250, локаль cs-cz, файлы хранятся в кодировке UTF-8, а страница генерируется с текстом заголовка HTTP / html; charset = UTF-8 и с метатегом UTF-8, если что-то из этого имеет значение.

Мой веб-сервер - Mongoose 6.7 с php 5.6 (cgi) в комплекте. Я также попробовал последнюю версию 7.3 (x86 и x64) с теми же результатами, однако @apokryfos в комментариях проверил ее с правильным шестым битом.

Ответы [ 2 ]

1 голос
/ 15 октября 2019

Корень проблемы - чувствительность к регистру: похоже, что некоторые ошибочные реализации MD5 не уменьшают регистр вывода md5. Две разные библиотеки были использованы на стороне клиента и на стороне сервера.

'A' starts at 0x41 = 0100 0001
'a' starts at 0x61 = 0110 0001
                       ^
                       here is the sixth bit
0 голосов
/ 15 октября 2019

Для JS используйте буфер или типизированный массив вместо строки. В противном случае вам нужно некоторое двоичное безопасное кодирование строк.

Вы можете XOR две строки в PHP полностью: $a ^ $b (не забудьте проверить длину).

См .: https://developer.mozilla.org/en-US/docs/Web/API/DOMString/Binary

Я получаю Bg0HdwB0dQkDDgcAdQR4ew8AcnB0dXtycgIBBHUGAXM = из PHP с вашим кодом, поэтому что-то еще происходит.

Можете ли вы предоставить версию PHP и сборку / исходный код?

...