可预测地生成大量伪随机数据

可预测地生成大量伪随机数据

我买了便宜的 2 TB HDD(每个 60 欧元),想检查它们是否返回使用前读取时输入的数据。我检查了一些廉价的拇指驱动器,方法是将我放在其中的大文件复制到它们并检查它们返回的数据的哈希值(并发现那些在实际存储容量耗尽后只是丢弃数据的驱动器)。不幸的是,我没有任何 2 TB 的文件。

我现在想要生成 2 TB 的伪随机数据,将其写入磁盘,并对磁盘进行哈希处理。然后我想将相同的数据直接写入哈希函数并获取它应该以这种方式产生的哈希值。伪随机函数不必以任何方式加密安全,它只需要快速生成高熵数据。

如果我编写一个脚本,仅对包含数字的变量进行哈希处理,将哈希值打印到标准输出,递增变量并重复,即使使用快速 CPU,数据速率也太慢了。慢了 5 个数量级(甚至不到 60 kByte/s)。

现在我可以尝试这样做,tee但这似乎是一个非常糟糕的主意,我不能一遍又一遍地重现相同的数据。

理想情况下,我会将一些短参数(数字、字符串,我不在乎)传递给程序,并在其标准输出中获取任意大量的数据,并且每次调用时的数据都是相同的。

答案1

只需加密零(***)。

加密正是您想要的。加密的零看起来像随机数据。解密后将其变回零。它是确定性的、可重复的、可逆的,因此只要您知道密钥并继续使用相同的密码设置(**)。

使用随机数据覆盖驱动器的示例cryptsetup

cryptsetup open --type plain --cipher aes-xts-plain64 /dev/deletedisk cryptodeletedisk
# overwrite with zeroes
pv < /dev/zero > /dev/mapper/cryptodeletedisk
# verify (also drop caches or power cycle)
echo 3 > /proc/sys/vm/drop_caches
pv < /dev/mapper/cryptodeletedisk | cmp - /dev/zero
### alternatively, run badblocks in destructive mode:
badblocks -w -b 4096 -t 0 -v -s /dev/mapper/cryptodeletedisk

这应该在具有 AES-NI 的现代系统上充分利用磁盘速度。

如果没有发现错误,您就知道驱动器已被随机数据完全覆盖,并且在读回时返回了正确的数据。


使用 cryptsetup 重复传输相同随机数据的示例(不涉及实际存储)。

在此示例中,/dev/zero我们不将其用作数据源,而是利用可以创建任意大且完全为零的稀疏文件:

# truncate -s 1E exabyte_of_zero
# cryptsetup open --type plain --cipher aes-xts-plain64 --readonly exabyte_of_zero exabyte_of_random
Enter passphrase for exabyte_of_zero: yourseed
# hexdump -C -n 64 /dev/mapper/exabyte_of_random
# cat /dev/mapper/exabyte_of_random | something_that_wanted_random_data

仅当您的文件系统支持稀疏文件且没有副作用时,这才有效(不适用于 tmpfs)。

注意:这只是一个例子;实际上创建这样的虚拟 EB 设备可能会产生副作用。将大小限制为适合您的用例的合理值,并将文件放在备份脚本不会尝试拾取并压缩它的位置等。


cryptsetup提供了一个可读的块设备,并且它是可查找的,因此您还可以使用它来开始比较文件中间某处的数据。您还可以使用它来分析任意偏移处的随机数据,并确保它确实是随机的并且不重复(*)。传统的 PRNG 通常要求您从头开始重新生成所有内容。


cryptsetup需要 root 权限(尽管生成的设备映射器设备可以让任何其他用户可读。)

没有 root 权限,您可以openssl通过加密零来生成随机数据。 (已经在评论中提到了。)

$ openssl enc -pbkdf2 -aes-256-ctr -nosalt \
      -pass pass:yourseed < /dev/zero \
      | hexdump -C -n 64
00000000  62 5e 3d cd 39 dc d6 a2  bb 73 2d 0f 63 b1 f1 75  |b^=.9....s-.c..u|
00000010  4d 84 f5 75 cb b6 1e 33  9c e8 41 9c 76 4b 7e 12  |M..u...3..A.vK~.|
00000020  c2 90 d5 93 2d a9 9e a0  48 bd b8 3e a5 1a d6 f7  |....-...H..>....|
00000030  2c a6 e0 07 4d 5a 45 31  13 dc ef 97 df 76 c5 b8  |,...MZE1.....v..|
00000040

这种方法也被建议coreutils 文档随机数据的来源作为一种方式“给定种子值,生成可重复的任意数量的伪随机数据”


您还可以使用传统的 PRNG 来代替加密零。只是我不知道有任何标准工具可以提供它。因此,这种方法涉及选择您选择的任何 PRNG 算法/库并编写几行代码来生成数据。

shred有一个很好的 PRNG,但你不能自己播种它,也不能通过管道传输它,所以这里无法使用它。

tee可以将数据从单个随机源复用到多个进程,但是它要求立即并行地消耗这些数据(例如:随机播放两个并行文本文件),因此这仅适用于数据必须相同但不必在以后再次再现的情况。


(*) 加密时,选择正确的密码设置非常重要。例如,aes-xts-plain在 2TB 后重复数据,这在aes-xts-plain64.所以不要再用了aes-xts-plain

(**) 不同的密码设置将导致不同的结果。此答案中显示的命令依赖于一些默认设置,因此从长远来看,数据可能不相同。例如,cryptsetup 可能使用 256 或 512 位密钥,而 openssl 使用默认迭代计数。

(***) 我们加密零的原因是内核为任意数量的零提供高性能数据源。否则,加密任何其他模式也同样有效。

答案2

如果您非常担心数据完整性,那么只需使用例如:ZFS,它具有内置的完整性检查,因为新的硬件可能没问题,但几年后它可能会变得很糟糕。

https://changelog.complete.org/archives/9769-silent-data-corruption-is-real

Here’s something you never want to see:

ZFS has detected a checksum error:

   eid: 138
 class: checksum
  host: alexandria
  time: 2017-01-29 18:08:10-0600
 vtype: disk

这意味着驱动器上存在数据错误。但这比典型的数据错误更糟糕——这是硬件未检测到的错误。与大多数文件系统不同,ZFS 和 btrfs 会在写入驱动器的每个数据块(数据和元数据)中写入校验和,并在读取时验证校验和。大多数文件系统不会这样做,因为理论上硬件应该检测到所有错误。但实际上,情况并非总是如此,这可能会导致静默数据损坏。这就是为什么我尽可能使用 ZFS。

相关内容