RC4
RC4
Rivest's 1987 trade secret, a shuffled table of 256 bytes and one swap per byte.
- Keyspace
- up to 2^2048
- Decode
- same options back
- Works on
- UTF-8 bytes, hex out
- Family
- 1 in permutation
Options
Access
- Create
create("rc4") - CLI
ciphers encode rc4 'Attack at dawn' --key 536563726574 - Tryplayground with the sample above
Ron Rivest wrote RC4 for RSA Security in 1987. RC stands for Ron's Code, he says so himself. For seven years it was a trade secret. Then in September 1994 someone posted the source to the Cypherpunks mailing list, anonymously. The name is still a trademark, so free code calls it ARC4 or ARCFOUR, alleged RC4. Same cipher.
After that it was everywhere. SSL in 1995, WEP on every Wi-Fi card in 1997, TLS in 1999. Why? Because it's tiny. The whole thing fits on a napkin.
How it runs
The state is a table S of 256 bytes, every value from 0 to 255 exactly once, and two indexes, i and j.
The key schedule starts with S in order. It walks i from 0 to 255, adds S[i] and the next key byte to j, and swaps S[i] with S[j]. The key repeats as many times as it takes. After 256 swaps the table is shuffled.
Then every keystream byte is three moves:
igoes up by one,jgoes up byS[i], and the two entries swap,- the byte is
S[S[i] + S[j]], all mod 256.
That's it. No rounds, no S-boxes, no blocks. The keystream gets XORed into the text, and decrypting is the same XOR again.
Keys and bytes
The key is hex, 2 to 512 digits, a whole number of bytes. Case doesn't matter and spaces are ignored. There's no IV. Text goes in as UTF-8, ciphertext comes out as lowercase hex.
Most RC4 keys out there are passwords, not hex. So a password goes in as its bytes. Secret is 536563726574:
const rc4 = create("rc4");
const key = "536563726574";
rc4.encode("Attack at dawn", { key }).text; // "45a01f645fc35b383552544b9bf5"
rc4.decode("45a01f645fc35b383552544b9bf5", { key }).text; // "Attack at dawn"
That's the third example from Wikipedia's RC4 page. Want the raw keystream? Encrypt zero bytes. Under Key (4b6579) the first ten come out as eb9f7781b734ca72a719, same as the page says.
Nothing is dropped from the start of the keystream. Some protocols throw the first bytes away, 768 or more, and call it RC4-drop. This is plain RC4, the one RFC 6229 and OpenSSL run.
Checked against
RFC 6229 publishes keystream for 14 keys, from 40 to 256 bits, at offsets up to 4096. The tests take three of those keys at offsets 0, 1008 and 4096. Every one of the 252 rows matched in a local run too. Then the three Wikipedia examples both ways, and UTF-8 text against openssl enc -rc4 with the legacy provider on.
No IV, so don't reuse the key
Same key, same keystream. Always. XOR two ciphertexts and the key drops out:
rc4.encode("Attack at dawn", { key }).text; // "45a01f645fc35b383552544b9bf5"
rc4.encode("Attack at dusk", { key }).text; // "45a01f645fc35b383552545f9ff0"
// XOR: "0000000000000000000000140405"
That's dawn XOR dusk. Rabbit at least has an IV for this. RC4 doesn't, so a protocol has to mix its own nonce into the key. WEP did exactly that, glued a 24-bit IV onto the key. Bad idea.
How broken is it
Very. Fluhrer, Mantin and Shamir showed in 2001 that the first keystream bytes leak the key when keys are related. That's how WEP fell. Klein found more leaks in 2005, and aircrack-ptw turned them into a 104-bit WEP key in under a minute.
The output isn't even random. Mantin and Shamir found the second byte is zero with probability 1/128, not 1/256. You can see it yourself. Take 200,000 random 16-byte keys and look at byte two. It's zero about twice as often as byte one.
RFC 7465 banned RC4 from every version of TLS in February 2015. So why is it here? Because CTFs and old puzzles still use it, and somebody has to decrypt them.
A key that isn't 2 to 512 hex digits, or isn't whole bytes, is an InvalidOptionError. A missing key is a MissingOptionError. On decode, an odd number of hex digits is a CipherError. No padding means only the UTF-8 check catches a wrong key, and a short message can still slip through as valid garbage.
Plain TypeScript, no integrity check, not constant time. Puzzles and learning, not secrets.