人类是强RNG还是弱RNG?

信息安全 随机的
2021-08-28 08:59:19

Thomas Pornin过去曾多次表示我不打算采购它们,如果他愿意,他可以与我争论)人类是糟糕的 RNG。

虽然我同意在头脑中生成密码的人工 RNG 通常很糟糕,但我想问一下计算机人工辅助的 RNG 是否同样糟糕。KeePass 有一个功能,您可以通过移动鼠标一段时间来为 RNG 播种,虽然我知道如果 KeePass 使用 /dev/urandom 它或多或少足够安全,但我过去曾使用过鼠标播种的 RNG。

我一直认为由人工输入辅助的 RNG 会比操作系统提供的标准 PRNG 更好。有人怎么能准确地预测我将如何移动鼠标,以什么速度,我暂停的频率等?

4个回答

的RNG很差。人们不善于在自己的头脑中生成随机值。他们只是不能随意思考尽管他们可以说服自己这样做。

另一方面,物理过程是相当好的熵源。移动鼠标。每秒几十次,鼠标测量自上次滴答以来它移动了多远,并将该信息发送到服务器。当你的手颤抖时,它往往会有点规律地颤抖,但生物学就是这样,每个基本动作都会受到一些抖动的影响,这恰好比鼠标的精度要大得多;即使经过大量训练,人的手也很难反复做完全相同的动作(否则会有更多像耶胡迪·梅纽因这样的人)。所以底线是鼠标移动测量包含一些熵。(请记住,“熵”在这里定义为“攻击者不知道的”;鼠标当然知道它移动了多少,因为实际上是鼠标发送了构建 RNG 的值。)

答案的另一半是聚合基于鼠标的 RNG 将使用数百甚至数千个度量,将它们全部累积并将它们浓缩成适当的种子,从而集中所有熵。这很简单:只需将所有值提供给加密哈希函数,例如 SHA-256,您将获得一个 256 位种子,其中包含所有源熵,无论它隐藏在测量的鼠标移动中的任何位置。散列函数对此有好处;它们减小了大小但保留了熵(直到散列函数输出大小,但 256 位对于所有目的来说都绰绰有余)。

攻击者可能会猜测用户会做圆圈,但很难让所有个人动作都正确,特别是因为心理学无法帮助他:人类用户自己不知道他的手部动作是如何转化为数字的。由于我们谈论的是数百个数字,因此可能的组合(即“熵”)的数量呈指数增长。将其与考虑新密码的人类用户进行对比:用户将遵循一些内在的“机智”思路选择字母,攻击者可以或多或少粗暴地猜测(例如,如果这些字母都是密码中某些单词的首字母)书中的句子,攻击者可以自动尝试他能找到的所有电子格式书中的所有句子);而且,更重要的是,人类用户不会

在密码中,长度并不代表强度——但长度不足可以非常有效地防止强度。

人类是非常差的随机性发生器,尤其是在要求时。

大多数用户会做一些事情之一,因为人类行为是相当可预测的。以鼠标为例,用户可能会左右或上下移动鼠标,直到根据程序产生足够的“随机性”。也许他们会把它绕一圈。他们不太可能做的是以真正随机的方式移动鼠标。如果有人关心,他们可以分析一组用户,推断可能的行为并从这些研究中提取有用的信息,以发现可用于攻击此类系统的模式。

很难获得真正的随机数据。

来自 C 和 C++ 的 Secure Programming Cookbook:不幸的是,大多数鼠标移动都遵循简单的轨迹,熵很少。最大熵发生在指针到达其目的地的大致附近并开始减速以锁定目标时。启动时通常也有相当多的熵。中间运动通常是相当可预测的。尽管如此,如果本地攻击不在您的威胁模型中,并且攻击者只能根据观察程序行为在特定时间范围内大致猜测鼠标进入屏幕的哪些部分,那么每只鼠标中可能存在相当多的熵事件,因为攻击者在任何给定时刻都无法猜测光标所在的像素。

使用以下小型 Python 脚本,尝试通过以“可重复”模式移动鼠标来生成 42 个零或一的序列。

import Tkinter

root = Tkinter.Tk()

lx,ly = (0, 0)
while True:
        x,y = root.winfo_pointerxy()
        if ((x-lx)**2+(y-ly)**2) > 42:
                print (x ^ y ^ lx ^ ly) & 1
                lx,ly = (x,y)

如果你有 Python 3.x,你也可以使用以下代码:

import tkinter
tkinter.NoDefaultRoot()
root = tkinter.Tk()
x = y = 0
while True:
    x2, y2 = root.winfo_pointerxy()
    if (x - x2) ** 2 + (y - y2) ** 2 > 42:
        print((x ^ y ^ x2 ^ y2) & 1)
        x, y = x2, y2

RNG 的质量是与输入或其他一些非秘密参数集相关性的问题。显然,如果 RNG 的输出与您知道的某些东西相关,那么通过允许您切掉可能的输出空间的大片区域来大幅降低熵 - 也许现在可以实际预期给定的 RNG 只输出 1,000 个数字中的一个,因为与广告中的 1,000,000 相反,这使得蛮力更加实用。

通过要求人类思考随机单词或短语构建的 RNG 实际上很差。原因与许多强相关:

  • 与文化的相关性,允许您使用英语词典来识别北美目标或专注于 1900-2000 的 PIN 码(这也是为什么其他语言的密码是一种不错的安全策略)
  • 与他人的相关性,允许您构建前 X 最常见密码的字典
  • 与自我的历史行为相关,允许您利用过去已知的密码,或挖掘社交媒体以获取生日或家乡等线索

请注意,许多“安全”PRNG 也基于非常可预测的输入,即系统时间。

关键是要认识到人类不一定是 RNG 的唯一元素。它仅充当种子。没有理由只允许您按原样输出种子,因此您可以对其应用各种函数来稀释相关性(一个基本但弱的示例是添加一个非常大的数字,乘以一个非常大的数字,然后然后取模)。

鼠标移动仅用作 Keepass 的 RNG 的种子。如果他们使用的函数能够合理地返回不相关的输入,则没有理由怀疑它不安全。(当然,我不能告诉你为什么他们不只是跳过鼠标并使用系统时间作为他们的种子,或者他们究竟使用什么功能以及它有多安全)