我正在学习Python。我无法弄清楚为什么hashlib.sha512(salt + password).hexdigest()
没有给出预期的结果。
我正在寻找相当于Ulrich Drepper的sha512crypt.c algorithm的纯Python实现。 (我花了一些时间来弄清楚我在寻找什么。)
根据我的Ubuntu 12.04系统上crypt
的手册页,crypt使用SHA-512(因为字符串以$ 6 $开头)。
下面的代码验证了当我调用Python的系统crypt包装器(即crypt.crypt())时,行为是否符合预期。我想使用hashlib.sha512或其他一些Python lib来产生与crypt.crypt()相同的结果。怎么样?
此代码显示我遇到的问题:
import hashlib, crypt
ctype = "6" #for sha512 (see man crypt)
salt = "qwerty"
insalt = '${}${}$'.format(ctype, salt)
password = "AMOROSO8282"
value1 = hashlib.sha512(salt + password).hexdigest() #what's wrong with this one?
value2 = crypt.crypt(password, insalt) #this one is correct on Ubuntu 12.04
if not value1 == value2:
print("{}\n{}\n\n".format(value1, value2))
根据crypt手册页,SHA-512是86个字符。上面代码中的crypt()
调用符合该调用。但是,hashlib.sha512的输出超过了86个字符,所以在这两个实现之间有一些差别......
以下是那些不想运行代码的人的输出:
051f606027bd42c1aae0d71d049fdaedbcfd28bad056597b3f908d22f91cbe7b29fd0cdda4b26956397b044ed75d50c11d0c3331d3cb157eecd9481c4480e455
$6$qwerty$wZZxE91RvJb4ETR0svmCb69rVCevicDV1Fw.Y9Qyg9idcZUioEoYmOzAv23wyEiNoyMLuBLGXPSQbd5ETanmq/
根据此处的初步反馈进行的另一次尝试。还没有成功:
import hashlib, crypt, base64
ctype = "6" #for sha512 (see man crypt)
salt = "qwerty"
insalt = '${}${}$'.format(ctype, salt)
password = "AMOROSO8282"
value1 = base64.b64encode(hashlib.sha512(salt + password).digest())
value2 = crypt.crypt(password, insalt) #this one is correct
if not value1 == value2:
print("{}\n{}\n\n".format(value1, value2))
答案 0 :(得分:11)
这是解决方案。在另一个问题上还有更多细节:Python implementation of sha512_crypt.c其中显示passlib的后端包含sha512_crypt的纯Python实现(如果操作系统上没有crypt.crypt(),则调用Python实现)。
$ sudo pip install passlib
import passlib.hash, crypt
ctype = "6" #for sha512 (see man crypt)
salt = "qwerty"
insalt = '${}${}$'.format(ctype, salt)
password = "AMOROSO8282"
value1 = sha512_crypt.encrypt(password, salt=salt, rounds=5000)
value2 = crypt.crypt(password, insalt)
if not value1 == value2:
print("algorithms do not match")
print("{}\n{}\n\n".format(value1, value2))
这是输出:
$6$qwerty$wZZxE91RvJb4ETR0svmCb69rVCevicDV1Fw.Y9Qyg9idcZUioEoYmOzAv23wyEiNoyMLuBLGXPSQbd5ETanmq/
$6$qwerty$wZZxE91RvJb4ETR0svmCb69rVCevicDV1Fw.Y9Qyg9idcZUioEoYmOzAv23wyEiNoyMLuBLGXPSQbd5ETanmq/
一个关键点是Passlib有一个sha512_crypt的纯Python实现,它将在系统没有当前Linux系统具有的crypt实现时使用(例如,http://www.akkadia.org/drepper/SHA-crypt.txt)。
请在此处查看PassLib的文档:
passlib - 用于python的密码哈希库 - Google Project Hosting
https://code.google.com/p/passlib/
Passlib 1.6.2文档 - Passlib v1.6.2文档
http://pythonhosted.org/passlib/
passlib-users - Google网上论坛
https://groups.google.com/forum/#!forum/passlib-users
新应用程序快速入门指南 - Passlib v1.6.2文档
http://pythonhosted.org/passlib/new_app_quickstart.html#sha512-crypt
passlib.hash.sha512_crypt - SHA-512 Crypt - Passlib v1.6.2文档
http://pythonhosted.org/passlib/lib/passlib.hash.sha512_crypt.html#passlib.hash.sha512_crypt
答案 1 :(得分:7)
crypt
的手册不精确(甚至误导)。 crypt
与“MD5”,“SHA-256”或“SHA-512”标记使用的算法实际上是在这些基元上构建算法 。它们是password-based key derivation functions,使用哈希来执行key strengthening。
good password hashing algorithm有两个属性:它必须将密码与唯一的盐组合在一起(以防止尝试一次破解多个密码),并且它必须很慢(因为这会比攻击者更多地伤害攻击者,因为攻击者需要尝试大量的组合)。像MD5和SHA系列这样的日常哈希算法设计得尽可能快,同时仍具有所需的安全属性。构建密码哈希算法的一种方法是采用加密哈希算法并多次迭代。虽然这个isn't ideal(因为有更好的技术使得构建专用硬件以进行密码破解变得更加困难),但它已经足够了。
Wikipedia article for crypt(3)
提供了一个简短的解释,并指出了主要来源。 Linux和FreeBSD的手册页很差,但Solaris's有足够的信息不会误导(请点击crypt.conf(4)
然后crypt_sha512
和其他人的链接)。您还可以阅读Is user password in ubuntu 13.04 in plain text?和Is there repetition in the Solaris 11 hash routine? Can I add some?
在Python中计算crypt
输出的正确方法是调用crypt.crypt
。
答案 2 :(得分:5)
您的密码长度不一样,因为crypt()
输出是base64编码的,你使用hexdigest作为value1
。
而不是hexdigest,你应该尝试做类似
的事情value1 = crypt_base64(hashlib.sha512(salt + password))
与crypt_base64
一样,bash implementation,最后一部分
doHash()
功能。