Skip to content

RC4

RC4

  • Do not use
  • Has biases for the first X output information.
  • It also has biases for all output information.

Security

  • The Key Scheduling Algorithm is bad

Key Reuse

you can’t re-use the same RC4 keystream to encrypt two different messages

Bit Flip Attacks

Padding Oracle

Bit Bias

When using random inputs the Second Bit

PoC:


Fluhrer, Mantin and Shamir attack

  • A 16-byte key can be computed from about 960 such keystreams because of the coloration of the outputs
    • The usually ways to fix this is dont use the first 3072 bytes of the output
    • Don't concat the IV to the key. Hash them instead.

In WEP if the IV is predictable either by a random number generator or other way it makes it easy to figure out the first byte of the keystream. Since RC4 only generates one byte at a time it makes it easy to figure out the next byte and continue down the line.

Klein, Dropping and Hashing

  • Reduces the operations needed to find the IV from a few million to 20,000

Implementation

from cryptopals_lib import *

def key_schedule(input_key):
	key_len = len(input_key)

	#Just a list of 0-255
	s_box = [x for x in range(256)]

	acc = 0
	for i in range(256):
		#
		acc += s_box[i] + input_key[i % key_len]
		acc %= 256

		#Swap the index I with the acc index
		s_box[acc], s_box[i] = s_box[i], s_box[acc]

	return s_box

def psudo_random_genreator(s_box):
	acc = 0 
	i = 0 

	while True:
		acc += 1 
		acc %= 256

		i += s_box[acc]
		i %= 256

		#Swap the index I with the acc index
		s_box[acc], s_box[i] = s_box[i], s_box[acc]

		index = (s_box[acc] + s_box[i]) % 256
		output = s_box[index]
		#print(index, output)
		yield output

def RC4(key):
	#Generate the s_box from the secret key
	s_box = key_schedule(key)
	#print(s_box)

	#Generate Keystream from s_box
	return psudo_random_genreator(s_box)


if __name__ == '__main__':
	#Test Vectors from https://tools.ietf.org/html/rfc6229

	key_stream = RC4(bytes_to_intarray(b"\x01\x02\x03\x04\x05", 1))

	output_data = b""
	for _ in range(32):
		output_data += int_to_bytes(next(key_stream))
	print(output_data.hex())

	assert(output_data.hex() == "b2396305f03dc027ccc3524a0a1118a86982944f18fc82d589c403a47a0d0919")