
本文详解如何在 javascript(前端/chrome 扩展)与 php(后端)间安全、一致地使用 rc4 算法完成加密与解密,重点解决因二进制数据传输导致的乱码、长度偏差问题,并通过 base64 编码确保字节完整性。
本文详解如何在 javascript(前端/chrome 扩展)与 php(后端)间安全、一致地使用 rc4 算法完成加密与解密,重点解决因二进制数据传输导致的乱码、长度偏差问题,并通过 base64 编码确保字节完整性。
RC4 是一种轻量级流密码算法,常用于对称加解密场景。但在实际 Web 开发中,JavaScript 与 PHP 的字符串处理机制存在本质差异:JavaScript 字符串基于 UTF-16 编码,而 PHP(尤其旧版本)默认按字节操作;直接传输原始 RC4 密文(含不可见控制字符、多字节 Unicode 码点)极易在 JSON 序列化、WebSocket 传输或 HTTP 解析过程中被截断、转义或损坏——这正是你遇到 encryptedText 在两端显示不一致(如 \u00d5\u00adCp\u0094K_... 多出转义序列)、解密失败的根本原因。
✅ 正确方案:始终对 RC4 密文进行 Base64 编码后再传输,解密前先 Base64 解码。Base64 将任意二进制数据映射为 ASCII 安全的可打印字符集(A–Z, a–z, 0–9, +, /),彻底规避编码歧义与传输污染。
以下是经过验证、严格对齐的完整实现:
✅ JavaScript(客户端)加密流程
function rc4Encrypt(key, plaintext) {
const S = Array.from({ length: 256 }, (_, i) => i);
let j = 0;
// KSA (Key-Scheduling Algorithm)
for (let i = 0; i < 256; i++) {
j = (j + S[i] + key.charCodeAt(i % key.length)) % 256;
[S[i], S[j]] = [S[j], S[i]]; // ES6 解构交换
}
// PRGA (Pseudo-Random Generation Algorithm)
let i = 0;
j = 0;
let cipher = '';
for (let k = 0; k < plaintext.length; k++) {
i = (i + 1) % 256;
j = (j + S[i]) % 256;
[S[i], S[j]] = [S[j], S[i]];
const keyIndex = S[(S[i] + S[j]) % 256];
const keystream = keyIndex ^ plaintext.charCodeAt(k);
cipher += String.fromCharCode(keystream);
}
return cipher;
}
// 使用示例
const plaintextObj = { data: 'yo, server' };
const jsonStr = JSON.stringify(plaintextObj); // → '{"data":"yo, server"}'
const encrypted = rc4Encrypt('test', jsonStr);
const base64Encoded = btoa(encrypted); // ✅ 关键:转为安全字符串
console.log('Encrypted (Base64):', base64Encoded);
// 发送时直接传 base64Encoded,无需再 JSON.stringify
ws.send(base64Encoded);✅ PHP(服务端)解密流程
function rc4Decrypt($key, $base64Cipher) {
// ✅ 第一步:Base64 解码,还原原始密文字节
$cipher = base64_decode($base64Cipher);
if ($cipher === false) {
throw new InvalidArgumentException('Invalid Base64 input');
}
$S = range(0, 255);
$j = 0;
// KSA
for ($i = 0; $i < 256; $i++) {
$j = ($j + $S[$i] + ord($key[$i % strlen($key)])) % 256;
[$S[$i], $S[$j]] = [$S[$j], $S[$i]];
}
// PRGA
$i = 0;
$j = 0;
$plaintext = '';
for ($k = 0; $k < strlen($cipher); $k++) {
$i = ($i + 1) % 256;
$j = ($j + $S[$i]) % 256;
[$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;
}
// WebSocket 消息处理示例
public function onMessage(ConnectionInterface $from, $msg) {
try {
// $msg 是来自 JS 的 Base64 字符串(如 "1a2b3c...")
$decryptedJson = rc4Decrypt('test', $msg);
$decoded = json_decode($decryptedJson, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new RuntimeException('Invalid JSON after decryption');
}
echo "Decrypted data: " . print_r($decoded, true);
// 后续业务逻辑...
} catch (Exception $e) {
error_log('RC4 decryption failed: ' . $e->getMessage());
$from->send(json_encode(['error' => 'Decryption failed']));
}
}⚠️ 关键注意事项
- 密钥一致性:JS 与 PHP 必须使用完全相同的密钥(包括大小写、空格),且建议避免纯 ASCII 密钥,生产环境应使用密码派生(如 PBKDF2)增强安全性。
-
不要对密文二次 JSON 化:
ws.send(base64Encoded)即可,切勿ws.send(JSON.stringify({data: base64Encoded}))—— 这会引入额外 JSON 转义层,破坏 Base64 格式。 -
字符编码统一:确保 PHP 文件保存为 UTF-8 无 BOM,且
mb_internal_encoding('UTF-8')已设置(虽 RC4 操作字节,但周边 JSON 处理依赖此)。 - RC4 已不推荐用于新系统:因其存在已知密码学弱点(如 Fluhrer-Martin-Shamir 攻击)。生产环境请优先选用 AES-GCM(需 Web Crypto API + OpenSSL 支持)等现代算法。
通过 Base64 编码桥接 JS 与 PHP 的字符串语义鸿沟,RC4 可稳定工作于跨平台通信场景。本文实现已在 Chrome 扩展 + PHP WebSocket 服务中实测通过,加密/解密结果 100% 可逆。
立即学习“PHP免费学习笔记(深入)”;



















