【问题标题】:Is it possible to generate random numbers using physical sensors?是否可以使用物理传感器生成随机数?
【发布时间】:2012-06-02 17:58:21
【问题描述】:

我听说有人使用光传感器、盖革计数器和其他物理传感器来生成随机数,但我对此表示怀疑。真的有办法通过测量物理世界(使用 Arduino 或任何其他微控制器)来生成随机数吗?如果是这样,这些数字真的会是随机的吗?

澄清一下:问题是关于使用微控制器收集的数据生成随机数的可行性,这些随机数可以可靠地应用于密码学——一种依赖设备熵的替代方法。

【问题讨论】:

  • 是如何实现的编程相关问题,还是从物理世界获得真实随机数的可行性理论问题?如果是后者 - 也许physics.SE 会更适合这个问题。
  • 澄清一下:问题是关于使用微控制器收集的数据生成可以可靠地应用于密码学的随机数的可行性 - 一种依赖设备熵的替代方案?
  • 线路噪声、放射性衰变等物理现象是随机的。但他们通常不是公正的。因此,必须小心确保您从这些来源获得可预测的分布。

标签: random arduino microcontroller avr entropy


【解决方案1】:

进行模拟“真实世界”测量通常是entropy(又名真实随机数据)的良好来源。模拟源总是会叠加一些不可预测的噪声,这些噪声可以被“捕获”。然而,如前所述,测量数据很少是无偏的。

模拟电气测量也可能或多或少容易受到无法控制的影响甚至来自外部的攻击,例如通过导致传感器饱和。 EMI 也可能会干扰测量;在通话期间将普通手机放置在合理靠近电路的位置很可能会对任何模拟信号造成严重破坏。

偏差

无偏、均匀分布的高熵数通常是人们想要的,因为它们的属性(不是)在某种程度上被归一化,因此可以更可靠地预测.

当以 10 位分辨率测量模拟输入时,理想情况下,从测量中收集的数字范围将涵盖从 0 到 1024 的所有值,并且每个值的出现频率(或概率)与来自那个范围。

实际上,这些值通常(或多或少)正态分布(高斯分布)围绕具有某些特征标准偏差的某个平均值,例如每个样本大约 500 @ 10 位。

去偏

因此,为了生成具有所需属性的随机值(见上文),需要进行一些去偏操作:需要某种randomness extractor

使用加密函数,如(单向)哈希函数或密码算法,通常也很容易产生所需的结果;但是这是有代价的:这些功能的“混合”在设计上是非常强大的,这使得在转换后无法确定源数据的质量(=随机性)。即使是最简单的确定性值序列(例如 {1,2,3,4,5...}全部。

在 µC 上生成熵

时间

在微控制器环境中,很少想到的一个很好的熵来源是事件的时间。使用高速计时器,可以通过读取计时器值以响应某些异步事件来收集真正的熵。这种与运行定时器无关的事件可能是用户按下按钮、另一个(子)系统或 IC 启动的通信开始,或者基本上任何其他未由 µC 触发的事件(或任何同步子系统)本身。

事实上,熵甚至可以从两个独立时钟源中获取;例如,通过另一个时钟对一个时钟的计时周期进行计时。这为 Atmel AVR µC(在 Arduino 中使用)打开了几个非常有趣的可能性,具体取决于 µC 的功能:

  • 大多数 AVR 都有内部 EEPROM 存储器。对该内存的写操作由一个独立于主系统时钟的专用计时器计时(-据报道有一些芯片(不是类型!)测量表明情况可能并非如此)(编辑:请注意,在某些 AVR 中,例如 ATTiny25/45/85,EEPROM 时序来自内部 RC 振荡器,因此当该振荡器也被选为系统时钟源时不会收集熵);这可能取决于主时钟源(内部 R/C 与外部晶体/谐振器)。因此,相对于主系统时钟,在写入 EEPROM 所需的时间内,预计会有一些(真正随机的)抖动,这又可以通过高速定时器/计数器来测量。

  • 较新的 AVR 能够让看门狗定时器产生软件中断而不是硬件复位。看门狗定时器在设计上由其自己的独立时钟源控制,从而产生可以测量的相对抖动。

  • 许多 AVR 都能够使用由外部 32kHz 晶振提供时钟的专用定时器/计数器,以提高实时测量的准确性。这个外部晶体是与主时钟不相关的另一个事件源。 (不然一开始多出来的水晶就没用了……)

后者似乎很有希望,因为它具有相对较高带宽的潜力:当使用运行速度明显更快的系统定时器对每个 32kHz 时钟周期进行计时时(在当前的 AVR @ 20 MHz 上可以实现 600+ 倍!)并且保守地假设每次测量只有 1 位熵,这导致 每秒 32000+ 位熵 - 远远超过一个 µC 自身消耗的量。

编辑:同时,我对 32kHz 定时器方法进行了一些简单的测试,短期结果似乎质量很低。每个样本生成的熵的上限似乎非常低,而我什至没有测试样本是否存在源自或多或少规则相移的非明显模式。这个结果可能是由于我的 DUT 的主时钟由外部晶体驱动,当在有限的时间范围内观察时,可以预期(在测量精度内)与 32kHz 石英的频率相同。延长两个样本之间的时间(分钟?)可能会返回良好的熵,但带宽非常低。 (注意:测量到的抖动也可能部分是由于中断延迟不同,具体取决于触发中断时执行的机器指令。)

编辑 #2:我的 DUT (ATmega1284) 的内部 RC 振荡器似乎会产生明显的频率抖动(几 kHz/s);当由外部 32kHz 晶体计时时,在这个振荡器上运行确实似乎产生了相当多的熵 (kBits/s)。

我最近在一个小实验中研究了前两种方法。在我的 DUT 上,EEPROM 时序通常比 WDT 更有利:

定时 EEPROM 写操作在每次写操作产生大约 4.82 位的熵,而看门狗定时器在频率方面似乎更稳定,每次看门狗超时产生大约 3.92 位。此外,EEPROM 的写入时间看起来更加平滑高斯分布,而 WDT 的分布似乎有些不对称并且有很多像差。

N.b.:为单个熵测量聚合多个“随机”事件实际上可能会降低所获得的熵:源中的快速随机波动可能会部分地相互补偿,从而产生与平均值偏差较小的结果值。因此,例如,在同一时间进行 32k 次计时(晶体的 每个 周期一次)可以预期比计时一秒(RTC 晶体的 32k 周期)更多的熵时间。

内存未初始化

Avr-gcc 编译的应用程序通常在执行用户代码之前将整个片上 RAM 清除为 0x00,即main()。将代码放入早期的 .init 部分可以在原始未初始化 RAM 内容被 gcc 的初始化例程覆盖之前访问它。

由于 RAM 的物理存储单元(位)的微小差异以及取决于一些真正的随机热噪声(和其他影响),当电源被(重新)应用于时,并非每个单元都会将自身初始化为相同的已知状态芯片。在上电后立即将芯片 RAM 的内容与某些功能相结合可以产生大量的熵以供以后使用。 - 这样做的缺点是它只能在电源关闭一段时间然后再次打开时才能可靠地工作。通过硬件、软件或外部信号进行的正常芯片重置将保留 RAM 以前的内容,因此不是(总是)一个好的熵源。但是,由于在相当复杂的应用程序中很难预测重置时整个系统 (RAM) 的状态,因此无论如何在重置后可能会立即收集一些熵。

带宽要求

必须根据其带宽和应用程序使用熵的带宽来查看熵源的质量。一些熵收集方法在几秒钟内可能不会产生超过一位的熵,而其他方法(不是真的在 µCs 上......)可能会产生 100 kbit/s 或更多。

必须注意,不能通过算法从现有熵“创建”新熵! - 一位熵不能通过计算转换为两位熵。

因此,一个人(平均而言)每单位时间消耗的(实际)熵不能多于同时从熵源收集的熵。

提案

当需要强随机数时,将一个或多个真实熵源与强 PRNG 组合并不少见,每次新熵可用时,使用收集到的熵来(重新)播种 PRNG。

与熵源在同一时间实际提供的数据相比,PRNG 可用于生成基本不可预测的数据。

作为一种特殊的 PRNG,可以使用加密密码函数,其中熵用于初始化和更新密码的密钥。

Linux 的/dev/urandom 通常是这样实现的。

结论

如上所述,在普通微控制器上生成真正的随机数是非常可行的。对于所有其他熵源,需要分析熵源提供的原始数字,了解它们包含的真实熵量以及每个时间单位产生的熵量,以确定该源是否适合用例与否。

真正的熵源和强 PRNG 的组合是通常实现的方法,也应该在微控制器上使用。

编辑:

PRNG 方法可能不是加密密钥生成的最佳选择。为此,应该只使用真正的随机位来生成安全密钥。收集这么多的熵可能需要一些时间(可能需要几秒钟),但由于在 µC 上通常不会非常频繁地执行密钥生成,因此这很可能是可以接受的。 (在每秒有数百或更多 SSL (HTTPS) 连接的负载较重的服务器上,这将是另一个问题......)

为了生成适合密钥生成的高质量高熵比特流,应使用上述randomness extractor

(另一方面,如果可以测量或估计源输出中的熵量,则可以简单地将密钥长度按(bitlength of key)/(entropy per bit sampled) 的因子缩放,然后直接使用来自熵源的原始低熵数据生成这个更长的密钥,然后它将具有与原始长度的完全随机密钥相同的整体熵。但是,如果这确实有效,则取决于密码如何处理不同长度的密钥。)

【讨论】:

  • Linux 的/dev/random 不是进入熵池的窗口,而/dev/urandom 在它之上实现了PRNG? FreeBSD 对两者都使用 PRNG。
  • 是的,看来你是对的。我会在我的答案中添加u :)
  • 令人印象深刻的答案! :) 我故意保持我的非技术性,因为问题似乎没有要求,但即使我尝试过,我也无法提供这种详细程度。
  • 非常感谢 :) - 有趣的是,这些关于 µC 的 RNG 纯粹是我过去两周左右的小项目刚刚。 - 在正确的时间偶然发现了这个问题,我猜 :)
  • 参见github.com/jj1bdx/avrhwrng 了解有关 Arduino Duemilanove 的实施示例(也适用于 UNO)。
【解决方案2】:

取决于传感器的范围、采样频率和灵敏度。您可以将传感器测量值视为位串或浮点数,这并不重要。关键是,最高有效位/前导小数不是很随机,它们甚至可能几乎不会改变。同样,最低有效位是不可靠的随机源,因为由于传感器灵敏度有限,它们可能会显示阶跃效应,并且取决于传感器,它们可能在时间上密切相关(例如,温度或电压将有逐渐变化的趋势)。然而,中间位/数字很可能是真正随机值的来源。

假设您有一个传感器输出 0 到 200 范围内的值,精度为 0.01。假设它是一个压力计,也许是一个分贝计。您需要对此进行广泛测试并查看特定传感器和环境的值分布,但我认为 10^0 和 10^-1 位置的数字很可能均匀分布且没有可辨别的顺序。

最适合的是可以进行非常精确的测量但无论如何都必须处理高噪声的传感器。这可能会造成问题,因为大多数传感器并非旨在提供不必要/不可靠的精度水平。此外,当然首选始终和任何地方(噪声除外)大致相同的测量值。宇宙背景辐射就是一个很好的例子。

【讨论】:

  • 所有关于传感器输出非随机部分的@Junuxx cmets 都是正确的。解决困难的一种方法是将原始传感器输出输入加密哈希,例如 MD5 或 SHA-256。一旦你有足够的原始数据来包含你需要的熵量,就可以将整个数据输入哈希,并得到一些好的随机位,这些位将包含相同数量的压缩后的熵。
【解决方案3】:

我一直在尝试使用硬件资源来生成随机数,到目前为止,它们似乎提供了一个不可预测的资源。如果使用白化技术,则可以减少/消除任何潜在的偏差,以允许它们产生均匀的随机整数序列。

如果您想尝试和实验,我已经实现了一个 Arduino 兼容库,它使用与看门狗定时器相关的抖动来生成随机数。初步结果表明它正在产生适合加密目的的结果。

可以在Code.google library repository找到

【讨论】:

    【解决方案4】:

    Google:真随机数生成器

    这就是你的做法,你制造噪音并对其进行采样。您无法从软件算法之类的确定性事物中创建真正随机的事物。

    【讨论】:

    • 将 OP 告诉“Google it”并不能回答问题。
    • 这不是一个stackoverflow问题,所以任何回答都是有效的。
    • 我不确定我是否理解,@old_timer。
    猜你喜欢
    • 1970-01-01
    • 2010-10-11
    • 1970-01-01
    • 1970-01-01
    • 2022-11-04
    • 1970-01-01
    • 1970-01-01
    • 2016-03-08
    • 1970-01-01
    相关资源
    最近更新 更多