This C code that you contacted would be very useful for inclusion in the question ;-) In any case, I went ahead and translated it into Python. Before you read this, let me say that I highly recommend you try it yourself and use my transcription as a guide. Translating algorithms from one programming language to another is usually a great practice when you want to improve your skills in one or both languages. Even if you do not know C, if you are familiar enough with Python to write programs in it, you should be able to get the gist of C code, as there are many similarities.
In any case, on the code.
import itertools, operator
First, a pseudo-random number generator, which was identified in the view as a linear congruent generator . This type of PRNG is a general algorithm that can be "customized" by selecting the specific values a , c and m (the variables mentioned in the Wikipedia article). The following is an implementation of a generalized linear congruent generator:
def prng(x, a, c, m): while True: x = (a * x + c) % m yield x
(hope you could come up with this yourself)
Now for the actual function:
def pass_to_key(passphrase):
The first step in the process is a hash (or "card") containing the passphrase provided to the 32-bit number. The WEP algorithm does this by creating a set of 4 bytes (thus 4 * 8 = 32 bits) that are initialized to zero.
bits = [0,0,0,0]
It goes through the string and XOR each character with one of the bytes; in particular, the character i is XOR'd in byte i % 4 .
for i, c in enumerate(passphrase): bits[i & 3] ^= ord(c)
Then these four bytes are combined together to form one 32-bit value. (Alternatively, I could write code to save them as a 32-bit number from the beginning)
val = reduce(operator.__or__, (b << 8*i for (i,b) in enumerate(bits)))
This 32-bit value is used as the seed for a linear congruent generator with specific values ββthat you can see in the code. As the original developer calculated these numbers, I have no idea.
keys = []
A linear congruent generator can produce up to 32 bits of output at a time. (In C, this is a data type restriction; in Python, I had to artificially apply it). I need 20 bytes to generate 4 40-bit (5-byte) WEP keys, so I will repeat PRNG 20 times,
for i, b in enumerate(itertools.islice(prng(val, 0x343fd, 0x269ec3, 1<<32), 20)):
and from each number, take only the third byte on the right (bit 16-23):
keys.append((b >> 16) & 0xff)
Why the third? Well, the bits on the upper end (4 on the right) tend not to change much, and those on the lower end can be predictable for many values ββof PRNG constants.
Subsequently, all that remains is to print the created bytes in groups of 5.
print ('%02x:%02x:%02x:%02x:%02x\n'*4) % tuple(keys)