#!/usr/bin/env python
def rc4crypt(data, key):
x = 0
box = range(256)
for i in range(256):
x = (x + box[i] + key[i % len(key)]) % 256
box[i], box[x] = box[x], box[i]
x = 0
y = 0
out = []
for byte in data:
x = (x + 1) % 256
y = (y + box[x]) % 256
box[x], box[y] = box[y], box[x]
out.append(byte ^ box[(box[x] + box[y]) % 256])
return out
def check_rc4_test_vector():
data = [0]*16
key = [0x01,0x02,0x03,0x04,0x05]
# See RFC 6229
testVector = [0xb2,0x39,0x63,0x05,0xf0,0x3d,0xc0,0x27,0xcc,0xc3,0x52,0x4a,0x0a,0x11,0x18,0xa8]
output = rc4crypt(data, key)
if (output != testVector):
print "=== Test Vectors Failed ==="
else:
print "=== Test Vectors Passed ==="
def get_rand_bytes(numberOfBytes):
out = []
file = open("/dev/urandom")
data = file.read(numberOfBytes)
for byte in data:
out.append(ord(byte))
file.close()
return out
class Challenger:
def __init__(self):
self.whichMessage = self.select_message()
def select_message(self):
byte = get_rand_bytes(1)[0]
if byte & 1 == 0:
return "m0"
else:
return "m1"
def Challenge(self,m0, m1):
key = get_rand_bytes(16)
if (self.whichMessage == "m0"):
return rc4crypt(m0, key)
elif (self.whichMessage == "m1"):
return rc4crypt(m1, key)
class Attacker:
def __init__(self, challenger):
self.challenger = challenger
def attack(self, numberOfTries):
byteHistogram = [0] * 256
m0 = [0,0]
m1 = [255,255]
for i in range(1, numberOfTries):
result = self.challenger.Challenge(m0, m1)
byteHistogram[result[1]]+=1
if byteHistogram[0] > byteHistogram[255]:
return "m0"
else:
return "m1"
def main():
import argparse
parser = argparse.ArgumentParser(description='This program demonstrates a trivial distinguishing attack on RC4 under the same message being encrypted under many keys.')
parser.add_argument('--trials', type=int,help='Set the number of times the attacker should iterate for.',default=2000)
check_rc4_test_vector()
challenger = Challenger()
print "Challenger says: " + challenger.whichMessage
args = parser.parse_args()
attacker = Attacker(challenger)
result = attacker.attack(args.trials)
print "Attacker says: " + result
if __name__ == "__main__":
main()