python SystemRandom/os.urandom是否总有足够的熵来获得良好的加密

Chr*_*ris 21 python linux random cryptography generator

我有一个密码生成器:

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))
Run Code Online (Sandbox Code Playgroud)

根据文档,SystemRandom使用os.urandom,它使用/ dev/urandom来丢弃随机的cryto位.在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是否适合制作强大的加密级密码?如果我尽快调用此函数,我会在某个时刻停止获取强大的cryto位,因为熵池已经耗尽了吗?

这个问题也可能是为什么的/ dev/urandom的总是产生强烈cryto位不在乎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)
Run Code Online (Sandbox Code Playgroud)

如果运行此并运行:

while 1 > 0:
    gen_pass()
Run Code Online (Sandbox Code Playgroud)

然后我非常可靠地得到一个如下图: 在此输入图像描述

在运行时制作图形cat /dev/urandom看起来很微笑并且cat /dev/random一无所获并且很快保持低电平(这也只是每隔3秒左右读出一个字节)

更新

如果我运行相同的测试,但有六个gen_pass()实例,我得到这个: 在此输入图像描述

所以看起来有些东西让我有足够的熵.我应该测量密码生成速率,并确保它实际上被限制,因为如果不是那么可能会发生一些可疑的事情.

更新

我找到了这个电子邮件链

这表示一旦池中只有128位,urandom将停止拉熵.这与上述结果非常一致,意味着在那些测试中我经常生成垃圾密码.

我之前的假设是,如果entropy_avail足够高(比如64位以上)那么/dev/urnadom输出就很好了.这似乎不是/dev/urandom为了/dev/random在需要时留下额外的熵.

现在我需要找出SystemRandom调用需要多少个真正的随机位.

And*_*ett 7

/dev/random和的输出之间有一个微妙的区别/dev/urandom.正如已经指出的那样,/dev/urandom不会阻止.这是因为它从伪随机数生成器获得其输出,从"实际"随机数中播种/dev/random.

输出/dev/urandom几乎总是足够随机 - 它是一个带有随机种子的高质量PRNG.如果你真的需要一个更好的随机数据源,你可以考虑使用一个带有硬件随机数生成器的系统 - 我的上网本中有一个VIA C7,它可以生成相当多的正确随机数据(我得到一致的99.9) kb/s出/ dev/random,545kb/s出/ dev/urandom).

顺便说一句,如果您正在生成密码,那么您可能需要查看pwgen- 它为您提供了可靠的密码:).