我对 Linux (Ubuntu) /etc/shadow 下存储的哈希 (ASCII) 代码感到困惑。
假设一个案例,设密码为'测试', 盐为'Zem197T4'。
通过运行以下命令,
$ mkpasswd -m SHA-512 test Zem197T4
生成一长串 ASCII 字符(这实际上是 Linux 在 /etc/shadow 中的存储方式)
$6$Zem197T4$oCUr0iMuvRJnMqk3FFi72KWuLAcKU.ydjfMvuXAHgpzNtijJFrGv80tifR1ySJWsb4sdPJqxzCLwUFkX6FKVZ0
当使用在线 SHA-512 生成器时(例如http://www.insidepro.com/hashes.php?lang=eng),生成的是一些十六进制代码,如下所示:
选项1)密码+盐
8d4b73598280019ef818e44eb4493c661b871bf758663d52907c762f649fe3355f698ccabb3b0c59e44f1f6db06ef4690c16a2682382617c6121925082613fe2
选项 2) 盐+密码
b0197333c018b3b26856473296fcb8637c4f58ab7f4ee2d6868919162fa6a61c8ba93824019aa158e62ccf611c829026b168fc4bf90b2e6b63c0f617198006c2
我相信这些十六进制代码应该与 mkpasswd 生成的 ascii 代码“相同”。但它们有什么关系呢?
希望有人能启发我吗?
答案1
在 Ubuntu/Debian 上mkpasswd
是软件包的一部分谁是并在其中实现mkpasswd.c
,实际上只是对crypt()
glibc 中声明的函数进行了复杂的包装unistd.h
。 crypt() 有两个参数:密码和盐。在本例中,密码为“test”,盐前缀为 SHA-512 哈希值“$6$”(请参阅SHA加密) 因此“$6$Zem197T4”被传递给 crypt()。
也许您注意到其中-R
的选项mkpasswd
决定了轮数。在文档中,您会发现默认值为 5000 发。这是为什么结果永远不会等于盐和密码的简单串联的第一个提示,它不仅仅被散列一次。事实上,如果你通过了,-R 5000
你会得到同样的结果。在这种情况下,“$6$rounds=5000$Zem197T4”被传递给 crypt(),glibc(Debian/Ubuntu 的 libc)中的实现从中提取方法和轮数。
crypt() 内部发生的事情比仅仅计算单个哈希更复杂,并且结果最终是 Base64 编码的。这就是为什么您显示的结果在最后一个“$”之后包含所有类型的字符,而不仅仅是 SHA-512 哈希的典型十六进制字符串中的 [0-9a-f]。该算法在已经提到的中有详细描述SHA 加密文档。
答案2
使用加盐密码的整个想法是,每次为同一密码生成哈希值时,都会得到不同的结果。这是为了避免彩虹表出现问题。
假设您的一个用户使用弱密码,比如 123456,您的 /etc/shadow 就会暴露。现在邪恶的黑客所要做的就是使用彩虹表找出弱密码并在其他位置再次使用它。