【发布时间】:2011-07-25 16:57:56
【问题描述】:
我有一个密码生成器:
import random, string
def gen_pass():
foo = random.SystemRandom()
length = 64
chars = string.letters + string.digits
return ''.join(foo.choice(chars) for _ in xrange(length))
根据文档,SystemRandom 使用 os.urandom,它使用 /dev/urandom 来丢弃随机加密位。在 Linux 中,您可以从 /dev/urandom 或 /dev/random 获取随机位,它们都使用内核可以获得的任何熵。可用的熵量可以通过 tail /proc/sys/kernel/random/entropy_avail 检查,这将返回一个类似于:129 的数字。数字越高,可用的熵就越多。 /dev/urandom 和 /dev/random 之间的区别在于 /dev/random 仅在 entropy_avail 足够高(例如至少 60)时才会吐出位,而 /dev/urandom 将始终吐出位。文档说 /dev/urandom 对加密有好处,您只需将 /dev/random 用于 ssl 证书等。
我的问题是 gen_pass 是否总是适合制作强加密级密码?如果我尽快调用此函数,是否会因为熵池已耗尽而在某个时候停止获取强加密位?
问题也可能是为什么 /dev/urandom 总是 产生强加密位 而 不关心 entropy_avail?
有可能 /dev/urandom 的设计使其带宽受限于您可以猜测的与熵量相关的周期数,但这是推测,我找不到答案。
这也是我的第一个 stackoverflow 问题,所以请批评我。我担心当知道答案的人可能知道背景时,我给出了很多背景。
谢谢
更新
在读取 /dev/urandom 时,我编写了一些代码来查看熵池:
import subprocess
import time
from pygooglechart import Chart
from pygooglechart import SimpleLineChart
from pygooglechart import Axis
def check_entropy():
arg = ['cat', '/proc/sys/kernel/random/entropy_avail']
ps = subprocess.Popen(arg,stdout=subprocess.PIPE)
return int(ps.communicate()[0])
def run(number_of_tests,resolution,entropy = []):
i = 0
while i < number_of_tests:
time.sleep(resolution)
entropy += [check_entropy()]
i += 1
graph(entropy,int(number_of_tests*resolution))
def graph(entropy,rng):
max_y = 200
chart = SimpleLineChart(600, 375, y_range=[0, max_y])
chart.add_data(entropy)
chart.set_colours(['0000FF'])
left_axis = range(0, max_y + 1, 32)
left_axis[0] = 'entropy'
chart.set_axis_labels(Axis.LEFT, left_axis)
chart.set_axis_labels(Axis.BOTTOM,['time in second']+get_x_axis(rng))
chart.download('line-stripes.png')
def get_x_axis(rng):
global modnum
if len(filter(lambda x:x%modnum == 0,range(rng + 1)[1:])) > 10:
modnum += 1
return get_x_axis(rng)
return filter(lambda x:x%modnum == 0,range(rng + 1)[1:])
modnum = 1
run(500,.1)
如果运行这个并同时运行:
while 1 > 0:
gen_pass()
然后我很可靠地得到一个如下所示的图表:
在运行 cat /dev/urandom 时制作图表看起来更微笑,而 cat /dev/random 下降到零并很快保持在低位(这也只是每 3 秒左右读取一个字节)
更新
如果我运行相同的测试但有六个 gen_pass() 实例,我会得到:
所以看起来有些东西使我有足够的熵。我应该测量密码生成率并确保它实际上被封顶,因为如果不是,那么可能会发生一些可疑的事情。
更新
我找到了这个email chain
这表示一旦池中只有 128 位,urandom 将停止拉熵。这与上述结果非常一致,这意味着在这些测试中我经常产生垃圾密码。
我之前的假设是,如果 entropy_avail 足够高(比如高于 64 位),那么 /dev/urnadom 输出就很好。情况并非如此,似乎/dev/urandom 旨在为/dev/random 留下额外的熵以备不时之需。
现在我需要找出 SystemRandom 调用需要多少真正的随机位。
【问题讨论】:
-
当然有可能——你可以从 /dev/urandom 中提取无限量的信息,而你没有无限量的熵。
-
就像我上面说的,我认为你可以设计成这样是不可能的,但我没有理由相信这一点。我需要做更多的研究。
-
@Chris 怎么样?熵必须来自某个地方——你不能只是把它变魔术。如果可以,我们的生活会轻松很多。
-
如果你假设熵生成的平均速率,然后你强制
/dev/urandom进程花费一定的时间(比如通过做一堆哈希),那么你可以或多或少地强制通过计算限制读取/dev/urandom的带宽,可能存在足够的熵。这需要内核知道它通常以多快的速度生成熵并动态限制带宽,或者使用一些下限假设来生成熵。 -
@Chris urandom 的重点是返回所需的尽可能多的数据 - 如果您需要保证熵,
/dev/random存在。
标签: python linux random cryptography generator