RC4 is a symmetric stream cipher. The same function encrypts and decrypts — XOR with the keystream is its own inverse.
Go
func rc4(key, data []byte) []byte {
// KSA (Key Scheduling Algorithm)
s := make([]byte, 256)
for i := range s { s[i] = byte(i) }
j := 0
for i := 0; i < 256; i++ {
j = (j + int(s[i]) + int(key[i%len(key)])) & 0xff
s[i], s[j] = s[j], s[i]
}
// PRGA (Pseudo-Random Generation Algorithm)
out := make([]byte, len(data))
ii, jj := 0, 0
for k := range data {
ii = (ii + 1) & 0xff
jj = (jj + int(s[ii])) & 0xff
s[ii], s[jj] = s[jj], s[ii]
out[k] = data[k] ^ s[(int(s[ii])+int(s[jj]))&0xff]
}
return out
}
func encryptHex(key []byte, body any) string {
j, _ := json.Marshal(body)
return hex.EncodeToString(rc4(key, j))
}
func decryptHex(key []byte, hexStr string) ([]byte, error) {
d, err := hex.DecodeString(hexStr)
if err != nil { return nil, err }
return rc4(key, d), nil
}
Python
def rc4(key: bytes, data: bytes) -> bytes:
# KSA
s = list(range(256))
j = 0
for i in range(256):
j = (j + s[i] + key[i % len(key)]) & 0xff
s[i], s[j] = s[j], s[i]
# PRGA
out, ii, jj = bytearray(len(data)), 0, 0
for k in range(len(data)):
ii = (ii + 1) & 0xff
jj = (jj + s[ii]) & 0xff
s[ii], s[jj] = s[jj], s[ii]
out[k] = data[k] ^ s[(s[ii] + s[jj]) & 0xff]
return bytes(out)
def encrypt_hex(key: str, body: dict) -> str:
import json
return rc4(key.encode(), json.dumps(body).encode()).hex()
def decrypt_hex(key: str, hex_str: str) -> dict:
import json
return json.loads(rc4(key.encode(), bytes.fromhex(hex_str)))
JavaScript / Node.js
function rc4(key, data) {
const s = Array.from({length: 256}, (_, i) => i);
let j = 0;
for (let i = 0; i < 256; i++) {
j = (j + s[i] + key.charCodeAt(i % key.length)) & 0xff;
[s[i], s[j]] = [s[j], s[i]];
}
const out = new Uint8Array(data.length);
let ii = 0, jj = 0;
for (let k = 0; k < data.length; k++) {
ii = (ii + 1) & 0xff;
jj = (jj + s[ii]) & 0xff;
[s[ii], s[jj]] = [s[jj], s[ii]];
out[k] = data[k] ^ s[(s[ii] + s[jj]) & 0xff];
}
return out;
}
function encryptHex(key, body) {
const json = new TextEncoder().encode(JSON.stringify(body));
return [...rc4(key, json)].map(b => b.toString(16).padStart(2, '0')).join('');
}
function decryptHex(key, hexStr) {
const bytes = Uint8Array.from(hexStr.match(/.{2}/g).map(h => parseInt(h, 16)));
const dec = rc4(key, bytes);
return JSON.parse(new TextDecoder().decode(dec));
}