为什么这个简单的 JavaScript XOR 加密算法不起作用?
Why is this simple JavaScript XOR encryption algorithm not working?
我正在尝试在 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 one, or this one,但我还是没能解决这个问题。
为什么这个 JavaScript 算法没有按预期工作?
小注1:由于无法遍历字符串的字符并在JavaScript中将它们一一替换,我使用了[= for
循环内的 16=] 运算符,以便将每个异或运算的输出附加到 result
变量。
小注2:为了规范化字符集,函数实际上returnbase64_encode($result)
和btoa(result)
在PHP 和 JS,分别。然后,为了解密它,decryptXor()
函数必须在迭代 result
变量之前对其进行解码。尽管如此,由于这与问题无关,所以我稍微简化了功能。在这种情况下,出于测试目的,在 text
变量中仅使用字母数字字符而在 key
变量中仅使用数字(反之亦然)会更安全。
您需要一些其他方法,例如 String#charCodeAt
or String.fromCharCode
以获得相同的结果。
主要问题是,您需要一个数值而不是 character/string。
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
您的主要问题是您正在使用 charAt instead of charCodeAt。 'someRandomText'.charAt(0)
的计算结果为 's'
。 's' ^ x === x
,因为 ^
运算符试图将两个操作数都转换为数字,而 Number('s')
是 NaN
。因此,当您与除数字字符以外的任何字符进行异或运算时,您只会得到键的值。
关于注释 1,您还有另一个问题:您不能只附加到字符串。如果您的算法产生字符串“567”,则无法知道它是通过连接“56”和“7”还是“5”和“67”创建的。随着字符串变长,这将成为一个更大的问题。您可以使用数组而不是字符串或将每个子字符串左零填充到相同的长度,或者如 Nina 建议的那样,您可以使用 String.fromCharCode.
将 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 one,
为什么这个 JavaScript 算法没有按预期工作?
小注1:由于无法遍历字符串的字符并在JavaScript中将它们一一替换,我使用了[= for
循环内的 16=] 运算符,以便将每个异或运算的输出附加到 result
变量。
小注2:为了规范化字符集,函数实际上returnbase64_encode($result)
和btoa(result)
在PHP 和 JS,分别。然后,为了解密它,decryptXor()
函数必须在迭代 result
变量之前对其进行解码。尽管如此,由于这与问题无关,所以我稍微简化了功能。在这种情况下,出于测试目的,在 text
变量中仅使用字母数字字符而在 key
变量中仅使用数字(反之亦然)会更安全。
您需要一些其他方法,例如 String#charCodeAt
or String.fromCharCode
以获得相同的结果。
主要问题是,您需要一个数值而不是 character/string。
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
您的主要问题是您正在使用 charAt instead of charCodeAt。 'someRandomText'.charAt(0)
的计算结果为 's'
。 's' ^ x === x
,因为 ^
运算符试图将两个操作数都转换为数字,而 Number('s')
是 NaN
。因此,当您与除数字字符以外的任何字符进行异或运算时,您只会得到键的值。
关于注释 1,您还有另一个问题:您不能只附加到字符串。如果您的算法产生字符串“567”,则无法知道它是通过连接“56”和“7”还是“5”和“67”创建的。随着字符串变长,这将成为一个更大的问题。您可以使用数组而不是字符串或将每个子字符串左零填充到相同的长度,或者如 Nina 建议的那样,您可以使用 String.fromCharCode.
将 XOR 的结果转换回单个字符