如何在Python中生成40/64位WEP密钥?
我这几个月一直在为这个问题苦恼,部分原因是因为这是我感兴趣的一个小项目,部分原因是我编程水平不太行。我在网上搜索了很多资料,但一直没有找到解决办法(除了一个小小的成功,见下文),所以我想试着问问专家们。
我想做的事情,正如标题所说,是根据一个密码短语生成一个40位或64位的WEP密钥,按照“事实上的”标准来做。(像http://www.powerdog.com/wepkey.cgi这样的网站可以生成预期的输出。)我已经写了一部分脚本,可以接收输入并将其写入文件;其中一个输入就是这个密码短语,处理后转换为小写。
很长一段时间我都不知道什么是“事实上的标准”,更不用说如何去实现它了。后来我偶然发现了一篇论文(http://www.lava.net/~newsham/wlan/WEP_password_cracker.pdf),这篇论文给了我一些启发(第18页有相关内容)。显然,密码短语是通过“异或运算”映射到一个32位的值,然后这个值被用作“线性同余伪随机数生成器”的种子(Python有好几种伪随机数生成器符合这个描述,但我不太清楚具体是哪一种),然后从这个结果中提取出几个比特。我不知道该如何实现这个,因为描述有点模糊。
我需要的是帮助我用Python写这个生成器,并且理解密钥是如何生成的。换句话说,我需要代码把“jackson”转换成“09F38AF593”。(请不要告诉我jackson = 09F38AF593; print (jackson))
我不是个程序员,所以能有解释我会很感激。
(是的,我知道WEP并不安全。)
2 个回答
我不太确定那个网站说的“事实标准”是什么,但我可以肯定的是,路由器制造商各自都有自己的实现方法。其实怎么做并不重要,只要相同的输入总能得到相同的输出就行;这样做是为了方便使用WEP的用户记住一个口令,而不是去记实际的十六进制密钥。你发的PDF里的方法也很模糊;它使用了一个没有定义的伪随机数生成器(PRNG),而且每种PRNG的结果都可能不同,文中还提到从每个结果中取“一个字节”,但没有说明具体是哪个字节。如果你想逆向工程某个特定路由器的方法,可以在帖子里提到这一点,我们或许能找到那个路由器的工作原理,但并没有一个统一的方法。
你提供的那段C代码如果能放在问题里就好了,真是太有用了 ;-) 不过没关系,我把它翻译成Python了。在你阅读之前,我想说的是,我非常鼓励你自己动手试试,把我的代码当作参考。把算法从一种编程语言翻译到另一种语言,通常是提升你在这两种语言技能的好方法。即使你不懂C,只要你对Python足够熟悉,能够写程序,你应该也能大致理解C代码,因为它们之间有很多相似之处。
好了,接下来是代码。
import itertools, operator
首先,伪随机数生成器在演示中被称为线性同余生成器。这种类型的伪随机数生成器是一种通用算法,可以通过选择特定的a、c和m的值来“定制”。下面是一个通用线性同余生成器的实现:
def prng(x, a, c, m):
while True:
x = (a * x + c) % m
yield x
(希望你能自己想到这一点)
接下来是实际的函数:
def pass_to_key(passphrase):
这个过程的第一步是将提供的密码短语哈希(或“映射”)成一个32位的数字。WEP算法通过创建一组4个字节(也就是4*8=32位)并将其初始化为零来实现这一点。
bits = [0,0,0,0]
它会遍历字符串,并将每个字符与其中一个字节进行异或运算;具体来说,字符i
会与字节i % 4
进行异或。
for i, c in enumerate(passphrase):
bits[i & 3] ^= ord(c)
这四个字节随后按顺序连接在一起,形成一个32位的值。(另外,我也可以从一开始就将它们存储为一个32位的数字)
val = reduce(operator.__or__, (b << 8*i for (i,b) in enumerate(bits)))
这个32位的值被用作线性同余生成器的种子,具体的值可以在代码中看到。原开发者是怎么找到这些数字的,我就不知道了。
keys = []
线性同余生成器一次可以产生最多32位的输出。(在C语言中这是数据类型的限制;在Python中我需要人为地强制这一点。)我需要20个字节来生成4个40位(5字节)的WEP密钥,所以我会让伪随机数生成器运行20次,
for i, b in enumerate(itertools.islice(prng(val, 0x343fd, 0x269ec3, 1<<32), 20)):
从每个数字中只取右边的第3个字节(位16-23):
keys.append((b >> 16) & 0xff)
为什么取第三个字节呢?因为高位(从右数第4个)通常变化不大,而低位对于许多伪随机数生成器常量来说可能是可预测的。
最后,只需将生成的字节按5个一组打印出来。
print ('%02x:%02x:%02x:%02x:%02x\n'*4) % tuple(keys)