Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this simple JavaScript XOR encryption algorithm not working?

Tags:

javascript

xor

I am trying to develop a (very) simple XOR encryption algorithm in JavaScript.

In PHP, the following encryption algorithm works as expected:

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

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

  return $result;
}

However, the following JavaScript algorithm does not work properly:

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;
}

A test case follows:

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

Apparently, the ^ operator is behaving differently between the two languages.

I have found some questions regarding the difference between PHP's and JavaScript's ^ operators, such as this one, this one or this one, but I still could not resolve this issue.

Why is this JavaScript algorithm not working as expected?


Minor note 1: Since it is not possible to iterate over the characters of a string and replace them one by one in JavaScript, I used the += operator inside the for loop in order to append the output of each XOR operation to the result variable.

Minor note 2: In order to normalize the character set, the functions actually return base64_encode($result) and btoa(result) in PHP and JS, respectively. Then, in order to decrypt it, the decryptXor() functions have to decode the result variables before iterating over them. Nonetheless, since this is not relevant to the question, I simplified the functions a bit. In this case, for the purpuses of testing, it is safer to use only alphanumeric characters in the text variable and only numerals in the key variable (or vice-versa).

like image 465
Renato Avatar asked Dec 17 '22 20:12

Renato


1 Answers

You need some other methods, like String#charCodeAt or String.fromCharCode for getting the same result.

The main problem is, you need a numerical value instead of the 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

A bit shorter version

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
like image 168
Nina Scholz Avatar answered Dec 31 '22 15:12

Nina Scholz