WEBKT

嵌入式Linux无HRNG?利用定时器、ADC、GPIO实现低开销软件随机数生成器

33 0 0 0

在嵌入式Linux系统中,当硬件随机数生成器(HRNG)不可用时,构建一个高性能、低开销的软件随机数生成器(SRNG)是保障系统安全的关键。核心思路是不依赖额外硬件,而是从现有硬件组件中挖掘物理熵,并通过精巧的软件机制将其注入内核的熵池(/dev/random/dev/urandom)。下面我将分享一个经过实践验证的方案,重点在于最小化CPU和内存开销

1. 熵源挖掘:从现有硬件中“淘金”

不要去碰那些昂贵的专用传感器,我们专注于系统已有的、能产生微小抖动的硬件资源:

  • 定时器/计数器:这是最理想的熵源之一。利用一个高精度定时器(如ARM的SysTick或通用定时器)读取其计数值。由于中断处理、任务调度、总线争用等不确定性,计数值的最低有效位(LSB)具有很高的随机性。可以周期性地(例如,每100ms)读取并累积到一个32位或64位的变量中。
  • ADC(模数转换器):即使ADC没有连接外部噪声源,其转换结果的低位比特也包含电路内部的热噪声和量化噪声。你可以读取一个未连接引脚的ADC值(或连接到一个悬空的引脚),其结果在低位比特上通常呈现良好的随机性。注意:连接到已定义电压(如VCC/GND)的引脚则不适合。
  • GPIO状态变化:监控一组GPIO引脚的状态变化(如边沿触发中断)。虽然GPIO本身不产生熵,但其变化的时间点(由外部事件或内部中断驱动)具有随机性。你可以记录这些事件的时间戳(使用高精度计时器)并将其哈希处理。

关键原则不要直接使用这些值作为随机数,而是将它们作为熵源,通过一个密码学哈希函数(如SHA-256)进行“白化”处理,提取出高质量的熵。

2. 注入内核熵池:高效且低开销的软件机制

Linux内核维护着一个熵池,用于所有随机数生成请求。我们的目标是将从硬件提取的熵安全、高效地注入其中。

  • 首选方案:add_randomness 内核API(通过内核模块)

    • 这是最直接、最高效的方法。编写一个轻量级的内核模块(LKM),在模块初始化时,创建一个内核线程(kthread)或利用工作队列(workqueue)。
    • 该线程周期性地(例如,每秒几次)从定时器、ADC、GPIO等读取原始数据。
    • 在内核空间,使用get_random_bytes函数(注意:这会消耗熵池,所以不能用于熵注入本身)或更底层的mix_pool_bytes函数(在较新内核中可能已废弃,需查阅对应版本的文档)来“混合”这些数据。实际上,更安全的做法是:在用户空间处理哈希,然后通过/dev/randomioctl接口或add_randomness函数(如果内核导出了该符号)注入。但最标准且推荐的方式是:
    • 通过用户空间程序写入 /dev/random:编写一个用户态守护进程,它从硬件读取数据,进行SHA-256哈希处理,然后将哈希结果(作为熵)写入 /dev/random 设备。这是最安全、最通用的方法,避免了内核模块的复杂性和稳定性风险。例如:
      # 将32字节的熵(来自哈希)注入熵池
      cat /path/to/your/entropy_file > /dev/random
      
      或者,使用ioctl命令 RNDADDENTROPY,这比cat更精确,能指定熵的数量。
    • 性能优化:在用户空间守护进程中,使用非阻塞I/O,并将读取、哈希、写入操作批处理。例如,每500ms收集一次数据,进行一次哈希,然后注入一次。这比频繁的小操作开销更低。
  • 避免的陷阱

    • 不要使用/dev/urandom作为熵源:它会消耗熵池,可能导致熵池耗尽,影响系统其他部分的随机数需求。
    • 不要盲目增加熵:每次注入的熵值(entropy_count)需要根据实际熵源质量估算。对于定时器和ADC的LSB,通常可以认为每比特有0.5~1 bit的熵。注入过多虚假熵会污染熵池,降低安全性。

3. 开源工具与最佳实践参考

  • haveged:这是一个著名的用户态熵收集守护进程,但它主要基于CPU定时器抖动,不直接利用ADC或GPIO。你可以借鉴其架构:它通过/dev/randomioctl接口注入熵,你可以修改其源代码,加入对特定硬件ADC或GPIO的读取逻辑。
  • rng-tools:这个工具包通常用于管理HRNG(如TPM、Intel RDRAND),但其rngd守护进程支持从自定义设备(通过-r选项)读取熵并注入内核。你可以将其配置为读取一个由你的用户态程序生成的伪设备文件(该文件内容来自你的硬件熵源哈希)。
  • 最佳实践
    1. 熵源混合:永远不要依赖单一熵源。混合使用定时器、ADC和GPIO时间戳,可以抵御针对单一熵源的攻击。
    2. 持续监测:监控内核熵池的熵计数(cat /proc/sys/kernel/random/entropy_avail)。确保在系统启动早期和负载高时,熵池不会耗尽。
    3. 密码学安全:在用户空间进行哈希处理时,使用SHA-256SHA-512等密码学安全的哈希函数。避免使用非密码学哈希(如CRC)。
    4. 延迟注入:对于高安全要求场景,可以将收集的熵先存储在安全区域(如加密的存储中),在需要时(如系统启动后)再批量注入,避免运行时被攻击者预测。

总结

在没有HRNG的嵌入式Linux平台上,通过挖掘现有硬件(定时器、ADC、GPIO)的物理熵,并利用用户态守护进程进行哈希处理后,通过/dev/random接口注入,是实现低开销SRNG的有效路径。关键在于理解熵的本质、避免直接使用原始数据、并采用批处理和混合熵源的策略havegedrng-tools的源码是极佳的参考起点,你可以根据具体硬件平台进行定制化改造,构建一个既安全又高效的随机数生成系统。

嵌入式安全手记 嵌入式Linux随机数生成熵池注入

评论点评