Перемещение паролей БД (хешированных и засоленных) (созданных с помощью Python 2) в новую систему (Python 3) UnicodeDecodeError - PullRequest
0 голосов
/ 17 января 2019

У меня есть приложение A, которое было сделано давно с python 2. Пароли имели такой формат в БД:

PBKDF2$sha256$10000$KlCW+ewerd19fS9f$l+5LgvcWTzghtz77086MSVG+q5z2Lij

В новой системе python 3 (назовем это app B) я настроил функции хеширования, и она всегда работает идеально, в новых системах пароли в БД выглядят так:

PBKDF2$sha256$10000$b'GAsfjwehd0x08C8'$b'w4oGw5vDjfgwerfweDjDFbwr3CoRrCkMOMwo9LOw1sWSg='

Теперь мне нужно переместить всех пользователей из приложения A в приложение B и сохранить пароли.

Первая ошибка, с которой я столкнулся после перемещения, была binascii error, invalid padding, поэтому я просто добавил отступ:

value['password']: PBKDF2$sha256$10000$KlCW+ewerd19fS9f$l+5LgvcWTzghtz77086MSVG+q5z2Lij

value['password'] += "=" * ((4 - len(value['password']) % 4) % 4)

После этого у меня было много разных попыток, и он всегда останавливался на:

Проблема:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0x97 in position 0: invalid start byte

Я думаю, что лучше всего настроить формат старого пароля, чтобы он совпадал с новыми паролями (которые работают), поэтому я сделал это:

value['password'] = "PBKDF2$sha256$10000$" + str(value['password'].split('PBKDF2$sha256$10000$')[1].split('$')[0].encode('utf-8')) +\
                "$" + str(value['password'].split('PBKDF2$sha256$10000$')[1].split('$')[1].encode('utf-8'))

Теперь старый пароль в БД выглядит так, как и новый PW:

PBKDF2$sha256$10000$b'KlCW+ewerd19fS9f'$b'$l+5LgvcWTzghtz77086MSVG+q5z2Lij=='

Новый check_function, который выбрасывает UnicodeDecodeError:

def check_hash(password, hash_):
    """Check a password against an existing hash."""
    if isinstance(password, str):
        password = password.encode('utf-8')
    algorithm, hash_function, cost_factor, salt, hash_a = hash_.split('$')
    assert algorithm == 'PBKDF2'
    """.decode("utf-8") transforms a bytes obj to string in python 3"""
    #actual_data += "=" * ((4 - len(actual_data) % 4) % 4)    
    #salt = salt.split("'")[1]
    #hash_a = hash_a.split("'")[1]
    salt = salt[2:][:-1]
    hash_a = hash_a[2:][:-1]
    password = password.decode("utf-8")

    print(hash_a, type(hash_a))
    print(salt, type(salt))   
    print(password, type(password))

    hash_a = b64decode(hash_a)   
    print ('after b64decode', hash_a, type(hash_a))
    # THE ERROR HAPPENS HERE: #
    # THE ERROR HAPPENS HERE: #
    # THE ERROR HAPPENS HERE: #
    hash_a = hash_a.decode("utf-8")

    print("after", hash_a, type(hash_a))

    print ("actually check", bytes(salt, 'utf-8'))
    hash_b = pbkdf2_bin(bytes(password, 'utf-8'), 
                        bytes(salt, 'utf-8'), 
                        int(cost_factor),
                        len(hash_a),
                        getattr(hashlib, hash_function))
    print(len(hash_a),len(hash_b))
    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 zip(hash_a, hash_b):
        #print("char", char_a, type(char_a), char_b, zip(hash_a, hash_b))
        diff |= ord(char_a) ^ ord(char_b)
    return diff == 0

Вплоть до ошибки все отпечатки идентичны для новых рабочих паролей и для старого неработающего пароля, поэтому я ничего не понимаю. Все выглядит одинаково, но выдает ошибку.

Я пытался сделать его как можно короче, потому что я думаю, что проблема должна быть в частях, которые я опубликовал, я могу ошибаться. При необходимости я публикую полные сценарии Python 2 и Python 3, но это очень много.

Итак, подведем итог:

hash_a = hash_a.decode("utf-8") работает для нового пароля, но не для старого, даже если оба имеют одинаковый формат и тип.

P.S .: под новым паролем я имею в виду пароли, которые были созданы с помощью нового скрипта, который я обновил до python 3.

P.S .: старые пароли были сгенерированы старым скриптом, который использовал python 2.

...