【发布时间】:2019-06-12 14:11:50
【问题描述】:
我需要将用户及其密码从 python 2 系统转移到 python 3 系统。
PW 哈希如下所示:
PBKDF2$sha256$10000$KlCW+ewerd19fS9f$l+5LgvcWTzghtz77086MSVG+q5z2Lij
在 python 2 系统中,我使用这些函数来检查哈希:
def check_hash(password, hash_):
"""Check a password against an existing hash."""
if isinstance(password, unicode):
password = password.encode('utf-8')
algorithm, hash_function, cost_factor, salt, hash_a = hash_.split('$')
assert algorithm == 'PBKDF2'
hash_a = b64decode(hash_a)
hash_b = pbkdf2_bin(password, salt, int(cost_factor), len(hash_a),
getattr(hashlib, hash_function))
assert len(hash_a) == len(hash_b) # we requested this from pbkdf2_bin()
# Same as "return hash_a == hash_b" but takes a constant time.
# See http://carlos.bueno.org/2011/10/timing.html
diff = 0
for char_a, char_b in izip(hash_a, hash_b):
diff |= ord(char_a) ^ ord(char_b)
return diff == 0
还有这个:
_pack_int = Struct('>I').pack
def pbkdf2_bin(data, salt, iterations=1000, keylen=24, hashfunc=None):
"""Returns a binary digest for the PBKDF2 hash algorithm of `data`
with the given `salt`. It iterates `iterations` time and produces a
key of `keylen` bytes. By default SHA-1 is used as hash function,
a different hashlib `hashfunc` can be provided.
"""
hashfunc = hashfunc or hashlib.sha1
mac = hmac.new(data, None, hashfunc)
def _pseudorandom(x, mac=mac):
h = mac.copy()
h.update(x)
return map(ord, h.digest())
buf = []
for block in xrange(1, -(-keylen // mac.digest_size) + 1):
rv = u = _pseudorandom(salt + _pack_int(block))
for i in xrange(iterations - 1):
u = _pseudorandom(''.join(map(chr, u)))
rv = starmap(xor, izip(rv, u))
buf.extend(rv)
return ''.join(map(chr, buf))[:keylen]
到目前为止我做了什么:
将代码复制到我的 python 3 脚本后,我不得不更改一些变量:
izip -> zip
我保留了 unicode:from past.builtins import unicode
我保留了xrange:from past.builtins import xrange
现在我没有脚本错误,但是在执行脚本后我在这里遇到了错误(在pbkdf2_bin 函数中):
rv = u = _pseudorandom(salt + _pack_int(block))
TypeError: must be str, not bytes
所以我通过将字节转换为 str 来修复它:
rv = u = _pseudorandom(salt + _pack_int(block).decode('utf-8'))
现在出现下一个错误(在pbkdf2_bin 函数中):
h.update(x)
TypeError: Unicode-objects must be encoded before hashing
我还用正确的编码解决了这个问题:
h.update(x.encode('utf-8'))
下一个错误:
File "C:\Users\User\Eclipse-Workspace\Monteurzimmer-Remastered\hash_passwords.py", line 123, in check_hash
getattr(hashlib, hash_function))
File "C:\Users\User\Eclipse-Workspace\Monteurzimmer-Remastered\pbkdf2.py", line 125, in pbkdf2_bin_old_2
u = _pseudorandom(''.join(map(chr, u)))
TypeError: ord() expected string of length 1, but int found
_pseudorandom(在pbkdf2_bin 函数中)的返回值存在问题。它必须被转换,所以我修复了它:
问题可能出在这里
#return map(ord, h.digest()) # throws the error
#return map(int, h.digest()) # returns nothing (length 0)
#return list(map(ord, h.digest())) # throws the error
return list(map(int, h.digest())) # seems to work with the correct length
最后一个错误在check_hash函数的末尾:
File "C:\Users\User\Eclipse-Workspace\Monteurzimmer-Remastered\hash_passwords.py", line 129, in check_hash
diff |= ord(char_a) ^ ord(char_b)
TypeError: ord() expected string of length 1, but int found
for char_a, char_b in zip(hash_a, hash_b):
diff |= ord(char_a) ^ ord(char_b)
char_a 是一个整数,而 chat_b 不是。我可以通过将 char_a 转换为真正的 char 来解决这个问题:
for char_a, char_b in zip(hash_a, hash_b):
diff |= ord(chr(char_a)) ^ ord(char_b)
最后我没有错误,但它告诉我输入的密码错误, 所以某处是一个错误,因为我知道密码是正确的,它适用于 python 2 应用程序。
编辑
有人提到了2to3库,所以我试了一下。总而言之,它做了同样的事情,我已经做了,问题也是一样的。
为赏金编辑
总结一下。我上面发布的 2 个函数来自 python 2 并在 python 2 中工作。
这个哈希:
PBKDF2$sha256$10000$r+Gy8ewTkE7Qv0V7$uqmgaPgpaT1RSvFPMcGb6cGaFAhjyxE9
这个密码是:Xs12'io!12
我可以在我的 python 2 应用程序上使用此密码正确登录。
现在我想在 python 3 中使用相同的两个函数,但即使我解决了所有错误,它仍然告诉我密码错误。
进口:
import hmac
import hashlib
from struct import Struct
from operator import xor
from itertools import izip, starmap
from base64 import b64encode, b64decode
import hashlib
from itertools import izip
from os import urandom
import random
import string
这些导入在 python 2 脚本中使用。
【问题讨论】:
-
我会试试
h.update(x)=>h.update(x.encode("utf-8")) -
我已经这样做了,您在阅读问题时错过了它。我知道它很长。感谢您的回复!
-
顺便说一句,但出于好奇:如果您想将代码转换为 Python 3,为什么要保留
unicode和xrange,而不是用它们的 Python 3 等效项替换它们? -
你应该做一些适当的调试:在两个代码中乱扔一些打印语句/函数,然后比较所有中间值(它可能比较
str和bytes,但内容应该相同) .这可能会告诉你脚本哪里出错了。 -
我已经完成了所有这些,我不想发布所有打印和测试,因为它会包含更多代码并且看起来很乱。我希望有人会立即认识到这个问题,但看起来,这是一个非常困难的问题。感谢您的回复!
标签: python python-3.x hash python-unicode