以下 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 中是否有更好或更安全的方法来解决这个问题?
以下 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 中是否有更好或更安全的方法来解决这个问题?
不,它并不完全安全。让我们看一下每个命令:
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。