2个不稳定版本
0.2.0 | 2022年9月6日 |
---|---|
0.1.0 | 2022年5月27日 |
#1320 在 算法 中
46KB
261 行
fast-erasure-shake-rng
一种基于海绵/双工构造和keccak-f排列的密码学安全的快速擦除(即前向安全)伪随机数生成器。
优先考虑安全性高于性能(速度)。
用法
要创建RNG的实例,最好使用 RngState::new_from_getrandom
。如果需要,可以使用 RngState::seed
添加额外的数据。要生成随机数据,使用 RngState::fill_random_bytes
填充缓冲区以包含随机字节,或使用 RngState::get_random_bytes
获取一个填充了随机字节的数组。如果需要向后安全性,可以使用 RngState::seed_with_getrandom
重新设置种子。
示例
基本用法
use fast_erasure_shake_rng::RngState;
let mut rng = RngState::new_from_getrandom().unwrap();
let key = rng.get_random_bytes::<32>();
重新设置种子以实现向后安全性
use fast_erasure_shake_rng::RngState;
let mut rng = RngState::new_from_getrandom().unwrap();
let key1 = rng.get_random_bytes::<32>();
// do other things ...
// later:
rng.seed_with_getrandom().unwrap();
let key2 = rng.get_random_bytes::<1000>();
添加额外的数据以减少对操作系统RNG的依赖
use fast_erasure_shake_rng::RngState;
let mut rng = RngState::new_from_getrandom().unwrap();
let mut user_dice_rolls = String::new();
std::io::stdin().read_line(&mut user_dice_rolls).unwrap();
rng.seed(user_dice_rolls.as_ref());
let key = rng.get_random_bytes::<32>();
确定性 & 可移植性
此伪随机数生成器是确定性的,这意味着在用相同的输入(或输入集)进行初始化时,它会产生相同的输出。因此,需要使用非确定性的随机源对其进行初始化。方法 RngState::new_from_getrandom
会创建一个用从操作系统 RNG(使用 getrandom
包 获取的随机数初始化的 PRNG 实例)初始化的 PRNG。
但是,PRNG 并非可移植/可复制的,这意味着对于相同的初始化材料,在不同平台和版本之间给出的输出可能不同。特别是,输出取决于目标端序和此包的版本号。如果您需要一个既确定又可移植的 PRNG,并且不需要重新初始化的能力,请使用标准 XOF,如 SHAKE256。
包特性
getrandom
(默认):启用对getrandom
包 的依赖。这可以通过例如RngState::new_from_getrandom
方法方便且安全地初始化 RNG。rand-core
:启用对rand_core
包 的依赖。这可以通过为RngState
实现rand_core
的 Rng 特性。
RNG 和密码学注意事项
攻击者控制的熵源
有一种广泛存在的观点,认为向 RNG 添加尽可能多的熵源总是一个好主意。不幸的是,事情并不那么简单。如果一个熵源受到攻击者的控制,实际上它可能被用来削弱或破坏 RNG。这确实需要恶意熵源知道或猜测来自其他(之前添加的)熵源的输入,或者知道 RNG 状态(即随机数池)。虽然这不是一个温和的假设,但恶意熵源可能比攻击者本身更容易获得这些输入。因此,在添加熵源时仍然需要谨慎。例如,请参阅 https://blog.cr.yp.to/20140205-entropy.html 以获取更多信息。
向后安全性
此 RNG 允许重新初始化,即将额外的熵哈希到状态中(在初始使用后)。这将提供向后安全性:即使攻击者在过去观察到了 RNG 状态,他在重新初始化操作发生后也无法预测 RNG 的输出。但实际上,如果攻击者能够看到 RNG 状态,那么如果您想要进行加密,那么 RNG 安全性并不是您面临的最大问题。因此,实际上几乎没有必要在一段时间后重新初始化 RNG。
设计
最初我以为只是在某个(安全的)置换上进行的海绵/双工构造就可以得到一个安全的 RNG,但不幸的是,这种构造并不是向前安全的。问题在于所使用的置换 keccak-f[1600] 是可高效逆的。因此,如果在获取随机字节后不执行重新初始化,那么获得 RNG 最终状态的攻击者只需反复应用逆置换即可找到自上次重新初始化以来发出的所有字节。
海绵结构为何对哈希函数或XOF仍然安全,是因为状态中容量部分的字节从未公开,这与我们需要假设的RNG正向安全性不同。解决问题的方式是在每次置换应用后清除状态中的容量部分。但这样,RNG就不维护一个秘密熵池:只给出一个速率大小的输出,就能计算出从那时起的所有未来值,直到重新播种。因此,我们实际上需要在状态中两个独立的容量部分:一个总是在输出随机字节后清除以实现正向安全性,另一个作为通常的(收集熵)状态部分。
详细描述
keccak状态通常由1600位组成,分为25个64位的通道。我们将它分为三个“区域”
- 我们称之为“速率区域”的区域,由顶部9个通道组成,因此大小为576位。
- 我们称之为“清除容量区域”的区域,由下一个8个通道组成,因此大小为512位。
- 我们称之为“容量区域”的区域,由最后8个通道组成,因此大小为512位。
我们现在定义对该状态的三种基本操作,这些操作将作为所有其他(面向用户)操作的构建块
- 我们称之为“输入”的基本操作。首先将576位输入数据异或到状态的“速率区域”。然后对状态应用keccak-f。
- 我们称之为“初始输出”的基本操作。首先输出“速率区域”中的字节作为随机输出字节。然后应用keccak-f。
- 我们称之为“中间输出”的基本操作。首先输出“速率区域”和“清除容量区域”中的字节作为随机输出字节。然后对状态应用keccak-f。
- 我们称之为“实现正向安全”的基本操作。清除(即,用零/空字节填充)“清除容量区域”。
第一个基本操作用于从输入中吸收熵到状态。接下来的两个用于从状态中挤压输出。操作“实现正向安全”创建了一个正向安全点:如果在此操作后状态泄露,攻击者将无法推断在此操作之前RNG执行的前向输入或输出。
在图中
Basic action 1: input State: Basic action 2: initial-output
┌────────┐
│Rate │
Xor input │ │ Output
───────────►│9 lanes ├───────────►
│ │
│ │
│ │
│ │
│ │
│ │
├────────┤
│Zeroized│
Leave alone │capacity│ Leave alone
│ │
│8 lanes │
│ │
│ │
│ │
│ │
├────────┤
│Capacity│
Leave alone │ │ Leave alone
│8 lanes │
│ │
│ │
│ │
Then apply Keccak-f1600 to "state". │ │ Then apply Keccak-f1600 to "state".
│ │
└────────┘
Basic action 3: intermediate-output State: Basic action 4: make-forward-secure
┌────────┐
│Rate │
Output │ │ Leave alone
◄───────────┤9 lanes │
│ │
│ │
│ │
│ │
│ │
│ │
├────────┤
│Zeroized│
Output │capacity│ Zeroize
◄───────────┤ │◄───────────
│8 lanes │
│ │
│ │
│ │
│ │
├────────┤
│Capacity│
Leave alone │ │ Leave alone
│8 lanes │
│ │
│ │
│ │
Then apply Keccak-f1600 to "state". │ │
│ │
└────────┘
将数据输入到RNG中的操作如下:使用简单的10*1位填充将数据填充到576位的倍数(72字节)。对于每个576位输入块,使用此块作为输入执行基本操作“输入”。最后,执行基本操作“实现正向安全”。
RNG输出数据的操作如下:首先,执行基本操作“初始输出”,并将其输出用作RNG输出的第一部分。如果请求更多数据(即,超过72字节),则重复执行基本操作“中间输出”,直到生成足够的输出。最后,执行基本操作“实现正向安全”。
待办事项
- 通过利用“清除状态部分”的中间结果来提高大请求的吞吐量
- 添加一个更快的擦除缓冲模式,以更有效地处理频繁的小请求
变更日志
见 CHANGELOG.md
。
文档
fast-erasure-shake-rng
的API文档可在https://docs.rs/secmem-alloc/*/fast_erasure_shake_rng/找到。
依赖关系
~110–280KB