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