为什么这种简单的JavaScript XOR加密算法不起作用?

时间:2018-09-21 19:51:31

标签: javascript xor

我正在尝试在JavaScript中开发一种(非常)简单的XOR加密算法。

在PHP中,以下加密算法可以正常工作:

function encryptXor($text, $key) {
  $result = '';

  for ($i = 0; $i < strlen($text); $i++)
    $result[$i] = $text[$i] ^ $key[$i % strlen($key)];

  return $result;
}

但是,以下JavaScript算法无法正常工作:

function encryptXor(text, key) {
  var result = '';

  for(var i = 0; i < text.length; i++)
    result += text.charAt(i) ^ key.charAt(i % key.length);

  return result;
}

一个测试用例如下:

Text: someRandomText
Key:  123456789
PHP output: B]^QgWY\V\fVLA
JS output:  12345678912345

显然,^运算符在两种语言之间的行为有所不同。

我发现了一些有关PHP和JavaScript的^运算符之间的区别的问题,例如this onethis onethis one,但我仍然无法解决此问题

为什么此JavaScript算法无法按预期工作?


次要注意事项1:由于无法遍历字符串的字符并在JavaScript中将它们一一替换,因此我在{{1内使用了+= }}循环,以便将每个XOR操作的输出附加到for变量。

次要注意事项2:为了规范字符集,这些函数实际上分别在PHP和JS中返回resultbase64_encode($result)。然后,为了对其解密,btoa(result)函数必须在对decryptXor()变量进行迭代之前对其进行解码。但是,由于这与问题无关,因此我对功能进行了一些简化。在这种情况下,出于测试目的,在result变量中仅使用字母数字字符,而在text变量中仅使用数字是安全的(反之亦然)。

2 个答案:

答案 0 :(得分:6)

您需要其他一些方法,例如String#charCodeAtString.fromCharCode来获得相同的结果。

主要问题是,您需要一个数字值而不是字符/字符串。

function encryptXor(text, key) {
    var result = '';

    for (var i = 0; i < text.length; i++) {
        result += String.fromCharCode(text.charCodeAt(i) ^ key.charCodeAt(i % key.length));
    }
    return result;
}

console.log(encryptXor('someRandomText', '123456789')); // B]^QgWY\V\fVLA

版本短一些

function encryptXor(text, key) {
    return Array.from(
        text,
        (c, i) => String.fromCharCode(c.charCodeAt() ^ key.charCodeAt(i % key.length))
    ).join('');
}

console.log(encryptXor('someRandomText', '123456789')); // B]^QgWY\V\fVLA

答案 1 :(得分:3)

您的主要问题是您使用的是charAt而不是charCodeAt'someRandomText'.charAt(0)的值为's''s' ^ x === x,因为^运算符试图将两个操作数都转换为数字,并且Number('s')NaN。因此,当您将非数字字符与任何其他字符进行异或运算时,您只需获取键的值即可。

关于注释1,您还有另一个问题:您不能仅附加到字符串。如果您的算法的结果为字符串“ 567”,则无法知道该字符串是由“ 56”和“ 7”或“ 5”和“ 67”串联而成的。随着字符串变长,这成为一个更大的问题。您可以使用数组而不是字符串,或者使用零填充每个子字符串相同的长度,或者按照Nina的建议,可以使用String.fromCharCode将XOR的结果转换回单个字符。