Будет ли python SystemRandom/os.urandom всегда иметь достаточную энтропию для хорошего крипто

У меня есть генератор паролей:

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 certs и тому подобное.

Мой вопрос будет gen_pass хорош для создания надежных паролей криптографического класса? Если я вызову эту функцию как можно быстрее, я перестану получать сильные критические биты в какой-то момент, потому что пул энтропии исчерпан?

Вопрос также может заключаться в том, почему /dev/urandom всегда производит сильные биты cryto и не заботится об энтропии_avail?

Возможно, что /dev/urandom сконструирован таким образом, что его пропускная способность ограничена количеством циклов, которые вы можете догадаться, будет коррелировано с количеством энтропии, но это предположение, и я не могу найти ответ.

Также это мой первый вопрос о стеке, поэтому, пожалуйста, критикуйте меня. Меня беспокоит то, что я много рассказывал, когда кто-то, кто знает ответ, вероятно, знает фон.

Спасибо

Обновление

Я написал некоторый код, чтобы посмотреть на энтропийный пул, пока /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()

Затем я довольно надежно получаю график, который выглядит так: enter image description here

Выполнение графика во время работы cat /dev/urandom выглядит smiler, а cat /dev/random падает до нуля и остается очень быстрым (это также выводится как байт каждые 3 секунды или около того)

Обновление

Если я запускаю тот же тест, но с шестью экземплярами gen_pass(), я получаю следующее: enter image description here

Итак, похоже, что что-то делает так, что у меня достаточно энтропии. Я должен измерить скорость генерации пароля и убедиться, что на самом деле он ограничен, потому что если это не так, то может произойти что-то подозрительное.

Обновление

Я нашел эту цепочку

Это говорит о том, что urandom перестанет тянуть энтропию, когда у пула только 128 бит. Это очень согласуется с приведенными выше результатами и означает, что в этих тестах я часто выпускаю нежелательные пароли.

Предполагалось, что если entropy_avail был достаточно высоким (скажем, выше 64 бит), то результат /dev/urnadom был хорошим. Это не так, кажется, что /dev/urandom был разработан, чтобы оставить дополнительную энтропию для /dev/random в случае, если она ему нужна.

Теперь мне нужно выяснить, сколько истинных случайных битов требуется вызову SystemRandom.

Ответ 1

Там тонкая разница между выходом /dev/random и /dev/urandom. Как уже отмечалось, /dev/urandom не блокируется. Это потому, что он получает свой результат от генератора псевдослучайных чисел, засеянных из "реальных" случайных чисел в /dev/random.

Вывод /dev/urandom будет почти всегда достаточно случайным - это высококачественный PRNG со случайным семенем. Если вам действительно нужен лучший источник случайных данных, вы можете рассмотреть возможность получения системы с генератором случайных чисел оборудования - у моего нетбука есть VIA C7, который может генерировать довольно много правильных случайных данных (я получаю согласованное 99,9 kb/s из /dev/random, 545kb/s из /dev/urandom ).

Как в стороне, если вы создаете пароли, вы можете посмотреть pwgen - он делает хорошие словарируемые пароли для вы:).

Ответ 2

/dev/random/ будет блокировать чтение, если ему требуется больше энтропии. /dev/urandom/ не будет. Так что да, если вы слишком быстро используете его, вы будете работать на энтропии. Наверное, все еще довольно сложно догадаться, конечно, но если вы действительно обеспокоены, вы можете читать байты от /dev/random/. В идеале, с неблокирующим циклом чтения и индикатором прогресса, чтобы вы могли перемещать мышь и генерировать энтропию, если это необходимо.