生成随机密码;为什么这个不便携?

Tay*_*mon 22 shell character-encoding binary tr portability

我想生成一个随机密码,并且这样做:

</dev/urandom tr -dc [:print:] | head -c 64
Run Code Online (Sandbox Code Playgroud)

在我运行 Ubuntu 的笔记本电脑上,这仅产生预期的可打印字符。但是,当我通过 ssh 连接到运行 Red Hat Enterprise Linux 的学校服务器并在那里运行时,我得到类似 的输出3!ri?b?Gr???1?H?<?oM????&?nMC[?Pb?|L%MP?????9??fL2q???IFmsd|l?K,但根本无法执行。这里可能出了什么问题?

cuo*_*glm 36

这是您的语言环境tr问题。

目前,GNU tr完全支持单字节字符。所以在使用多字节编码的语言环境中,输出可能很奇怪:

$ </dev/urandom LC_ALL=vi_VN.tcvn tr -dc '[:print:]' | head -c 64
`?pv???Z????c?ox"?O???%?YR??F?>?????ov???????^,<H ???>
Run Code Online (Sandbox Code Playgroud)

shell 会正确打印多字节字符,但 GNUtr会删除它认为不可打印的字节。

如果您希望它稳定,则必须设置语言环境:

$ </dev/urandom LC_ALL=C tr -dc '[:print:]' | head -c 64
RSmuiFH+537z+iY4ySz`{Pv6mJg::RB;/-2^{QnKkImpGuMSq92D(6N8QF?Y9Co@
Run Code Online (Sandbox Code Playgroud)

  • +1 因为这让我意识到(在 Unix/Linux 上使用 shell 只有大约 30 年),stdin/stdout/stderr 重定向不必定位在它适用的命令之后**。 (16认同)
  • @orion:外壳将正确打印字符。在这种情况下,这是 tr 问题。它删除了它认为不可打印的字节,使结果变得奇怪。 (2认同)

zwo*_*wol 11

考虑代替

$ dd if=/dev/urandom bs=48 count=1 status=none | base64
imW/X60Sk9TQzl+mdS5PL7sfMy9k/qFBWWkzZjbYJttREsYpzIguWr/uRIhyisR7
Run Code Online (Sandbox Code Playgroud)

这有两个好处:

  • 您只从随机设备中读取了 48 个字节,而不是 ~8KB;如果同一主机上的其他进程需要随机数,一次全部耗尽 8KB 可能是一个严重的问题。(是的,可以说没有人应该使用阻塞随机设备,但人们确实这样做了。)

  • 的输出base64几乎不包含具有特殊含义的字符。(对于根本没有,钉| tr +/ -_在端,以及(如实施例)确保的字节数输入base64是3的倍数)

以这种方式生成的密码正好有 384 位的熵,这比您所做的少一些(日志2 96 64 ≈ 421.4),但对于大多数用途来说已经足够了(256 位的熵安全地处于“仍在猜测何时除了RSA 密钥,AFAIK之外,Sun 会烧毁”领土)。