Python:random.random()植入哪里?

标签 python random cryptography random-seed

说我有一些python代码:

import random
r=random.random()

r的值通常从哪里来?
如果我的操作系统没有随机数,那么它将在何处播种呢?
为什么不建议将其用于加密?有什么方法可以知道随机数是多少?

最佳答案

遵循da代码。

要查看random模块在系统中的“位置”,您可以在终端中执行以下操作:

>>> import random
>>> random.__file__
'/usr/lib/python2.7/random.pyc'

这为您提供了.pyc(“已编译”)文件的路径,该文件通常与可以找到可读代码的原始.py并排放置。

让我们看看/usr/lib/python2.7/random.py中发生了什么:

您将看到它创建了Random类的实例,然后(在文件底部)“将该”实例的方法“提升”为模块功能。整洁的把戏。当将random模块导入任何地方时,将创建该Random类的新实例,然后初始化其值并将方法重新分配为模块的功能,从而使其在每次导入时都相当随机(erm ...或每个Python解释器实例)的基础。
_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

那么...如果xNone(未指定种子)会发生什么?好吧,让我们检查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

注释已经说明发生了什么。此方法尝试使用操作系统提供的默认随机数生成器,如果没有,则将当前时间用作种子值。

但是,等等...那_urandom(16)到底是什么呢?

好吧,答案就在此random.py文件的开头:
from os import urandom as _urandom
from binascii import hexlify as _hexlify

Tadaaa ...种子是一个来自os.urandom的16字节数字

假设我们使用的是文明的操作系统,例如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,您将始终获得整数138577 ...某种程度上打败了目的(有关伪随机数生成的信息,请参见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

    关于Python:random.random()植入哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27284943/

    相关文章:

    javascript - 将数字分成 4 个随机数

    python - 加密模块是 Fernet 安全的,我可以用该模块进行 AES 加密吗?

    java - ECC ASN1 签名验证失败

    python - 不明白我收到的错误?

    Python:将列单元格内的每个数组转换为单个字符串

    python - 使用Selenium后如何使用BeautifulSoup导航到页面

    0到1之间的Javascript随机数

    javascript - 在 THREE.js 中为螺旋星系生成粒子

    python - 在 PDF Django Weasyprint 中附加 img 文件

    python - Flask/Tornado 中的 Gzip 响应