用于生成加密安全随机字符串的 Unix 命令

信息安全 密码学 linux 随机的 Unix
2021-08-23 19:38:08

以下 Unix 命令在加密上是否可以安全地随机生成 20 个字符(仅限 a-zA-Z0-9)?

dd if=/dev/urandom bs=256 count=1 2> /dev/null | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c20

在 Unix 中是否有更好或更安全的方法来解决这个问题?

1个回答

不,它并不完全安全。让我们看一下每个命令:

dd if=/dev/urandom bs=256 count=1 2> /dev/null

这将从/dev/urandom加密安全的随机源中读取单个 256 字节块。问题从这里开始,与这个 256 字节限制有关。事实上,你甚至不需要在dd这里使用。下一个命令完全能够自行从块设备中读取。

LC_ALL=C tr -dc 'A-Za-z0-9'

此命令删除所有非字母数字字符。LC_ALL=C 字符集限制为纯 ASCII,其中[:alnum:]将匹配 62 个字符。符号和不可打印的字符将被删除。现在的问题是这个命令只分配了 256 个字节,那么如果这些字节中的字母数字太少怎么办?如果只有几个字节与过滤器匹配,该tr命令将愉快地接受 256 个字节的输入并仅吐出几个字节的输出。

head -c20

此命令只是将输出截断为 20 个字节。实际输出将在 0 到 20 个字符之间变化。*从统计上看,它最有可能每次输出全部 20 个字符。


获得随机字母数字字符的更好方法可以用更少的命令来完成。这将根据需要tr读取尽可能多的数据,/dev/urandom并不断地将字母数字 ASCII 输出到下一个命令。一旦head获得它所要求的 20 个字节,它将关闭管道,导致tr停止读取随机数据并退出。这是你应该使用的:

LC_ALL=C tr -dc '[:alnum:]' < /dev/urandom | head -c20

这将保证 20 个随机字符,等效强度为 log 2 (62 20 ) ≈ 119.1 位。

您还可以将其转换为 shell 脚本函数,以便更轻松地从命令行生成密码。此特定函数将密码的字符数作为参数。如果未指定参数,则默认为 20 个字符:

newpass() {
    LC_ALL=C tr -dc '[:alnum:]' < /dev/urandom | head -c${1:-20}
}

* 风险主要是理论上的。每个字节有 (256 - 62) / 256 的机会(约 76%)不是字母数字。至少 256 - 20 个字节不是字母数字的概率非常低,但非零: (194 / 256) 236 ≈ 3.8 × 10 -28