XOR 字符串:JS 与 PHP

XOR strings: JS vs PHP

我尝试在 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);
}

那位发生了什么事?

示例input/output:

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 header 生成的text/html;charset=UTF-8 和元标记 UTF-8(如果有任何这些问题)。

我的网络服务器是捆绑了 php 5.6 (cgi) 的 Mongoose 6.7。我也尝试了最新的 7.3(x86 和 x64),结果相同,但是评论中的@apokryfos tested it 第六位正确。

对于 JS,使用缓冲区或类型化数组而不是字符串。否则你需要一些二进制安全字符串编码。

您可以完整地异或 PHP 中的两个字符串:$a ^ $b(不要忘记长度检查)。

参见:https://developer.mozilla.org/en-US/docs/Web/API/DOMString/Binary

我从 PHP 得到 Bg0HdwB0dQkDDgcAdQR4ew8AcnB0dXtycgIBBHUGAXM= 和你的代码,所以其他事情正在发生。

你能提供 PHP 版本和构建/源代码吗?

问题的根源在于区分大小写:似乎 MD5 的一些错误实现并没有降低 md5 输出的大小写。在客户端和服务器端使用了两个不同的库。

'A' starts at 0x41 = 0100 0001
'a' starts at 0x61 = 0110 0001
                       ^
                       here is the sixth bit