RC4, also known as ARC4 or ARCFOUR, is a stream cipher.

In [1]:
from collections import namedtuple

class RC4:
    def __init__(self):
        self.S = list(range(256))
        self.i = 0
        self.j = 0
In [2]:
RC4()
Out [2]:
<__main__.rc4 at>
In [3]:
class RC4(RC4):
    def init_key(self, key, rounds=256):
        for i in range(256):
            self.S[i] = i
        
        j = 0
        for i in range(rounds):
            i %= 256
            j = (j + self.S[i] + key[i % len(key)]) % 256
            x = self.S[i]
            self.S[i] = self.S[j]
            self.S[j] = x
In [4]:
r = RC4()
r.init_key(b"testkey")
In [5]:
class RC4(RC4):
    def get_byte(self):
        self.i = (self.i + 1) % 256
        self.j = (self.j + self.S[self.i]) % 256
        
        x = self.S[self.i]
        self.S[self.i] = self.S[self.j]
        self.S[self.j] = x
        
        return self.S[(self.S[self.i] + self.S[self.j]) % 256]
In [6]:
r = RC4()
r.init_key(b"testkey", rounds=2**16)
[r.get_byte() for _ in range(5)]
Out [6]:
[63, 174, 37, 137, 119]
In [7]:
class RC4(RC4):
    def get_buf(self, size):
        buf = bytearray(size)
        for i in range(size):
            buf[i] = self.get_byte()
        return buf
In [8]:
def check_output(key, expected):
    r = RC4()
    r.init_key(key.encode('ascii'))
    
    size = int(len(expected) / 2)
    return r.get_buf(size).hex().upper() == expected.upper()

check_output("Key", "EB9F7781B734CA72A719")
check_output("Wiki", "6044DB6D41B7")
check_output("Secret", "04D46B053CA87B59")
Out [8]:
True
In []: