Search code examples
javascriptphpencryption

rc4 encryption and decryption in javascript and php


I try to encrypt data in my javascrip client using the rc4 algorithm and decrypt it with my php server. I found this code here. I use the word 'test' as my key for testing purposes. When I encrypt the text and then log it I get weird characters (probably the encryption), but when I try to decrypt it in my php server I do get the same characters but with extra or less characters. Example:

Javascript client console:

text before encrypting: {"data":"yo, server"}
background.js:958 encryptedText: Õ­CpK_ô72O1×½ËûÂ$ó
background.js:907 sent data: "Õ­CpK_\u001fô72O1×½ËûÂ$ó" 

Php console:

"Õ­CpK_\u001fô72O1×½ËûÂ$ó""\u00d5\u00adCp\u0094K_\u001f\u00f472O1\u00d7\u0082\u00bd\u00cb\u00fb\u00c2$\u00f3"

I use the following rc4 function in my client javascript (Chrome extension):

  // Send data
    function sendWebSocketData(data) {
        if (ws && ws.readyState === WebSocket.OPEN) {
            ws.send(JSON.stringify(data))
            console.log('sent data: ' + JSON.stringify(data))
        } else {
            console.log('DEBUG: WebSocket connection is not open.')
        }
    }



function rc4(key, str) {
    var s = [], j = 0, x, res = '';
    for (var i = 0; i < 256; i++) {
        s[i] = i;
    }
    for (i = 0; i < 256; i++) {
        j = (j + s[i] + key.charCodeAt(i % key.length)) % 256;
        x = s[i];
        s[i] = s[j];
        s[j] = x;
    }
    i = 0;
    j = 0;
    for (var y = 0; y < str.length; y++) {
        i = (i + 1) % 256;
        j = (j + s[i]) % 256;
        x = s[i];
        s[i] = s[j];
        s[j] = x;
        res += String.fromCharCode(str.charCodeAt(y) ^ s[(s[i] + s[j]) % 256]);
    }
    return res;
}
    let text = { data: 'yo, server' }
        console.log('text before encrypting: ' + JSON.stringify(text))
    
        encryptedText = rc4('test', JSON.stringify(text))
        console.log('encryptedText: ' + encryptedText)
    
        sendWebSocketData(encryptedText)

And the following rc4 function for my php server:

public function onMessage(ConnectionInterface $from, $msg)
{
    // Process the received message (handle JSON data)
    rc4('test', $msg);

    echo $msg;

    $decoded = json_decode($msg, true);
    echo json_encode($decoded);
}
function rc4($key, $str)
{
    $s = array();
    for ($i = 0; $i < 256; $i++) {
        $s[$i] = $i;
    }
    $j = 0;
    for ($i = 0; $i < 256; $i++) {
        $j = ($j + $s[$i] + ord($key[$i % strlen($key)])) % 256;
        $x = $s[$i];
        $s[$i] = $s[$j];
        $s[$j] = $x;
    }
    $i = 0;
    $j = 0;
    $res = '';
    for ($y = 0; $y < strlen($str); $y++) {
        $i = ($i + 1) % 256;
        $j = ($j + $s[$i]) % 256;
        $x = $s[$i];
        $s[$i] = $s[$j];
        $s[$j] = $x;
        $res .= $str[$y] ^ chr($s[($s[$i] + $s[$j]) % 256]);
    }
    return $res;
}

Solution

  • I fixed it by first encoding it to base64

    php:

    function rc4Decrypt($key, $cipher)
    {
        // RC4 decryption algorithm
        $S = range(0, 255);
        $j = 0;
    
        for ($i = 0; $i < 256; $i++) {
            $j = ($j + $S[$i] + ord($key[$i % strlen($key)])) % 256;
            // Swap values of $S[$i] and $S[$j]
            [$S[$i], $S[$j]] = [$S[$j], $S[$i]];
        }
    
        $i = 0;
        $j = 0;
        $plaintext = '';
    
        for ($k = 0; $k < strlen($cipher); $k++) {
            $i = ($i + 1) % 256;
            $j = ($j + $S[$i]) % 256;
            // Swap values of $S[$i] and $S[$j]
            [$S[$i], $S[$j]] = [$S[$j], $S[$i]];
    
            $keyIndex = $S[($S[$i] + $S[$j]) % 256];
            $keystream = $keyIndex ^ ord($cipher[$k]);
            $plaintext .= chr($keystream);
        }
    
        return $plaintext;
    }
    
    $jsoned = json_encode($data);
        $encryptedText = rc4Decrypt("test", $jsoned);
        $base64Encoded = base64_encode($encryptedText);
    
        $interface->send($base64Encoded);
    

    javascript:

    function rc4Encrypt(key, plaintext) {
        // RC4 encryption algorithm
        var S = [];
        for (var i = 0; i < 256; i++) {
            S[i] = i;
        }
    
        var j = 0;
        for (var i = 0; i < 256; i++) {
            j = (j + S[i] + key.charCodeAt(i % key.length)) % 256;
            // Swap values of S[i] and S[j]
            var temp = S[i];
            S[i] = S[j];
            S[j] = temp;
        }
    
        var i = 0;
        var j = 0;
        var cipher = '';
        for (var k = 0; k < plaintext.length; k++) {
            i = (i + 1) % 256;
            j = (j + S[i]) % 256;
            // Swap values of S[i] and S[j]
            var temp = S[i];
            S[i] = S[j];
            S[j] = temp;
    
            var keyIndex = S[(S[i] + S[j]) % 256];
            var keystream = keyIndex ^ plaintext.charCodeAt(k);
            cipher += String.fromCharCode(keystream);
        }
    
        return cipher;
    }
    
      var key = "test";
    
            var jsoned = JSON.stringify(plaintextObject); // turn it inoto plain text
            var encryptedText = rc4Encrypt(key, jsoned); // encrypt it
            var base64Encoded = btoa(encryptedText); // convert to base64
    
            ws.send(base64Encoded);