说我有一些python代码:
import random
r=random.random()
一般来说,种子的价值在哪里? 如果我的操作系统没有随机,那么播种在哪里呢? 为什么不推荐用于加密?有没有办法知道随机数是什么?
答案 0 :(得分:12)
关注 da code 。
要查看系统中random
模块“存在”的位置,您可以在终端中执行此操作:
>>> import random
>>> random.__file__
'/usr/lib/python2.7/random.pyc'
它为您提供了.pyc
(“已编译”)文件的路径,该文件通常与可以找到可读代码的原始.py
并排放置。
让我们看看/usr/lib/python2.7/random.py
中发生了什么:
您将看到它创建了Random
类的实例,然后(在文件的底部)“提升”该实例的方法到模块函数。干净的把戏。在任何地方导入random
模块时,会创建该Random
类的新实例,然后初始化其值,并将这些方法重新分配为模块的功能(使其在一个模块上非常随机)每个进口基础)
_inst = Random()
seed = _inst.seed
random = _inst.random
uniform = _inst.uniform
triangular = _inst.triangular
randint = _inst.randint
这个Random
类在其__init__
方法中唯一能做的就是播种它:
class Random(_random.Random):
...
def __init__(self, x=None):
self.seed(x)
...
_inst = Random()
seed = _inst.seed
那么......如果x
是None
(没有指定种子),会发生什么?好吧,让我们检查一下self.seed
方法:
def seed(self, a=None):
"""Initialize internal state from hashable object.
None or no argument seeds from current time or from an operating
system specific randomness source if available.
If a is not None or an int or long, hash(a) is used instead.
"""
if a is None:
try:
a = long(_hexlify(_urandom(16)), 16)
except NotImplementedError:
import time
a = long(time.time() * 256) # use fractional seconds
super(Random, self).seed(a)
self.gauss_next = None
评论已经告诉我们发生了什么......这种方法试图使用OS提供的默认随机生成器,如果没有,那么它将使用当前时间作为种子值。
但是,等等......那么_urandom(16)
那件事到底是什么?
嗯,答案就在这个random.py
文件的开头:
from os import urandom as _urandom
from binascii import hexlify as _hexlify
Tadaaa ...种子是一个16字节的数字来自os.urandom
假设我们处于文明的操作系统中,例如Linux(带有真正的随机数生成器)。 random
模块使用的种子与执行:
>>> long(binascii.hexlify(os.urandom(16)), 16)
46313715670266209791161509840588935391L
为什么指定种子值被认为不那么好的原因是random
函数不是真正的“随机”...它们只是一个非常奇怪的序列数字。但是,鉴于相同的种子,该序列将是相同的。你可以自己试试:
>>> import random
>>> random.seed(1)
>>> random.randint(0,100)
13
>>> random.randint(0,100)
85
>>> random.randint(0,100)
77
无论何时或如何,甚至 ,您运行该代码(只要用于生成随机数的算法保持不变),如果您的种子是1
,将始终得到整数13
,85
,77
...哪种方式失败了目的(参见this关于伪随机数生成)另一方面,有use cases但实际上这可能是一个理想的功能。
这就是为什么被认为是“更好”依赖于操作系统随机数发生器。这些通常是基于硬件中断来计算的,这些中断是非常非常随机的(它包括用于硬盘读取的interruptions,由用户键入的键击,移动鼠标...)在Linux中,即O.S.生成器是/dev/random。或者,有点挑剔,/dev/urandom
(这就是Python的os.urandom
实际在内部使用的)不同之处在于(如前所述)/dev/random
使用硬件中断来生成随机序列。如果没有中断,/dev/random
可能会耗尽,您可能需要等待一段时间才能获得下一个随机数。 /dev/urandom
在内部使用/dev/random
,但它保证始终为您准备好随机数。
如果您正在使用Linux,只需在终端上执行cat /dev/random
(并准备点击 Ctrl + C ,因为它会真正开始输出,非常随机的东西)
borrajax@borrajax:/tmp$ cat /dev/random
_+�_�?zta����K�����q�ߤk��/���qSlV��{�Gzk`���#p$�*C�F"�B9��o~,�QH���ɭ�f��̬po�2o�(=��t�0�p|m�e
���-�5�߁ٵ�ED�l�Qt�/��,uD�w&m���ѩ/��;��5Ce�+�M����
~ �4D��XN��?ס�d��$7Ā�kte▒s��ȿ7_���- �d|����cY-�j>�
�b}#�W<դ���8���{�1»
. 75���c4$3z���/̾�(�(���`���k�fC_^C
Python使用OS随机生成器或时间作为种子。这意味着我可以想象Python random
模块潜在弱点的唯一地方就是使用它:
time.time
始终报告同一时间的设备中(基本上是时钟损坏)如果您担心random
模块的实际随机性,您可以直接转到os.urandom
或使用pycrypto加密库中的随机数生成器。那些可能更随机。我说更随机因为......
图像灵感来自其他SO answer