随机数生成器
VeraCrypt随机数生成器(RNG)用于生成主加密密钥、辅助密钥(XTS模式)、盐值和密钥文件。它在随机存取存储器(内存)中创建一个随机值池。这个320字节长的池由以下来源的数据填充:
- 鼠标移动
- 按键操作
- Mac OS X和Linux:内置随机数生成器生成的值(包括/dev/random和/dev/urandom)
- 仅适用于MS Windows:MS Windows CryptoAPI(每隔500毫秒定期收集)
- 仅适用于MS Windows:网络接口统计信息(NETAPI32)
- 仅适用于MS Windows:各种Win32句柄、时间变量和计数器(每隔500毫秒定期收集)
从上述任何来源获取的值在写入池之前,会被分割成单个字节(例如,一个32位的数字会被分割成四个字节)。然后,这些字节通过模28加法运算(而不是替换池中的旧值),分别写入池的游标位置。写入一个字节后,池游标的位置会向前移动一个字节。当游标到达池的末尾时,其位置会被设置为池的开头。每写入16个字节到池中后,会自动对整个池应用池混合函数(见下文)。
池混合函数
此函数的目的是进行扩散[2]。扩散将单个“原始”输入位的影响尽可能地分散到池状态的更多部分,这也隐藏了统计关系。每写入16个字节到池中后,会对整个池应用此函数。
池混合函数的描述:
- 设R为随机数池。
- 设H为用户选择的哈希函数(SHA - 512、BLAKE2S - 256或Whirlpool)。
- l = 哈希函数H输出的字节大小(即,如果H是BLAKE2S - 256,则l = 20;如果H是SHA - 512,则l = 64)
- z = 随机数池R的字节大小(320字节)
- q = z / l - 1(例如,如果H是Whirlpool,则q = 4)
- R被分割成l字节的块B0...Bq。
对于0 ≤ i ≤ q(即,对于每个块B),执行以下步骤:
- M = H (B0 || B1 || ... || Bq) [即,使用哈希函数H对随机数池进行哈希处理,生成哈希值M]
- Bi = Bi ^ M
- R = B0 || B1 || ... || Bq
例如,如果q = 1,随机数池将按以下方式混合:
- (B0 || B1) = R
- B0 = B0 ^ H(B0 || B1)
- B1 = B1 ^ H(B0 || B1)
- R = B0 || B1
生成的值
随机数生成器池的内容永远不会直接导出(即使VeraCrypt指示随机数生成器生成并导出一个值)。因此,即使攻击者获得了随机数生成器生成的值,他也无法确定或预测(使用所获得的值)会话期间随机数生成器生成的任何其他值(从随机数生成器生成的值确定池的内容是不可行的)。
每当VeraCrypt指示随机数生成器生成并导出一个值时,随机数生成器通过执行以下步骤来确保这一点:
- 将从上述来源获得的数据按上述方式添加到池中。
- 将请求的字节数从池复制到输出缓冲区(复制从池游标的位置开始;当到达池的末尾时,复制从池的开头继续;如果请求的字节数大于池的大小,则不生成值并返回错误)。
- 反转池中每个位的状态(即,0变为1,1变为0)。
- 将从上述某些来源获得的数据按上述方式添加到池中。
- 使用池混合函数转换池的内容。注意:该函数使用用户选择的加密安全单向哈希函数(有关更多信息,请参阅上面的池混合函数部分)。
- 将转换后的池内容按以下方式异或到输出缓冲区:
- 将输出缓冲区写入游标设置为0(缓冲区的第一个字节)。
- 从池的游标位置读取一个字节,并将其与输出缓冲区中写入游标位置的字节进行异或运算。
- 将池游标的位置向前移动一个字节。如果到达池的末尾,则将游标位置设置为0(池的第一个字节)。
- 将输出缓冲区写入游标的位置向前移动一个字节。
- 对输出缓冲区的每个剩余字节(其长度等于请求的字节数)重复步骤b - d。
- 导出输出缓冲区的内容,即随机数生成器生成的最终值。
设计起源
随机数生成器的设计和实现基于以下工作:
- Peter Gutmann的《软件生成实用强随机数》[10]
- Carl Ellison的《加密随机数》[11]
下一部分 >>