Как использовать Scrypt для генерации хэша для пароля и соли в Python
Я хотел бы использовать scrypt, чтобы создать хэш для паролей и солей моих пользователей. Я нашел две ссылки, но есть вещи, которые я не понимаю о них.
Они используют функции шифрования и дешифрования scrypt. Один шифрует случайную строку, а другой шифрует соль (что выглядит неправильно, поскольку для расшифровки используется только пароль, а не соль). Похоже, что функция дешифрования используется для проверки пароля / соли как побочного эффекта дешифрования.
Исходя из всего, что я понимаю, мне нужна функция деривации ключей (KDF), а не шифрование / дешифрование, и то, что KDF, вероятно, генерируется и используется scrypt для шифрования / дешифрования. Фактический KDF используется за кулисами, и я обеспокоен тем, что слепое следование этим примерам приведет к ошибке. Если для генерации и проверки пароля используются функции шифрования / дешифрования scrypt, я не понимаю роль зашифрованной строки. Имеет ли значение его содержание или длина?
2 ответа
Вы правы - функции scrypt, с которыми эти две ссылки играют, являются утилитой шифрования файлов scrypt, а не базовым kdf. Я медленно работал над созданием автономного хеша паролей на основе scrypt для python и сам столкнулся с этой проблемой.
Утилита scrypt file выполняет следующие действия: выбирает параметры scrypt n/r/p, специфичные для вашей системы, и параметр "min time". Затем он генерирует 32-байтовую соль, а затем вызывает scrypt(n,r,p,salt,pwd)
создать ключ на 64 байта. Двоичная строка, которую возвращает инструмент, состоит из: 1) заголовка, содержащего значения n, r, p и соль, закодированную в двоичном виде; 2) контрольная сумма заголовка sha256; и 3) копия контрольной суммы, подписанная hmac-sha256, используя первые 32 байта ключа. После этого он использует оставшиеся 32 байта ключа, чтобы AES зашифровал входные данные.
Есть несколько последствий этого, которые я могу видеть:
входные данные не имеют смысла, так как они фактически не влияют на используемую соль, а encrypt() каждый раз генерирует новую соль.
Вы не можете настроить рабочую нагрузку n, r, p вручную или любым другим способом, кроме неудобного параметра min-time. это не небезопасно, но довольно неудобно контролировать фактор работы.
после того, как вызов decrypt регенерирует ключ и сравнит его с hmac, он сразу же отклонит все, если ваш пароль неверен - но если он верен, он продолжит также дешифровать пакет данных. Это большая дополнительная работа, которую злоумышленнику не придется выполнять - ему даже не нужно извлекать 64 байта, только 32, необходимые для проверки подписи. Эта проблема не делает ее небезопасной, но делать работу, которую не делает ваш злоумышленник, никогда не желательно.
нет возможности настроить солт-ключ, размер производного ключа и т. д. текущие значения не так уж и плохи, но, тем не менее, они не идеальны.
ограничение "максимального времени" утилиты дешифрования является неправильным для хеширования пароля - каждый раз, когда вызывается дешифрование, он оценивает скорость вашей системы и "угадывает", может ли он вычислить ключ в течение максимального времени, что больше накладных расходов для вашего злоумышленника не нужно делать (см. #3), но это также означает, что расшифровка может начать отклонять пароли при большой загрузке системы.
Я не уверен, почему Колин Персиваль не сделал код выбора kdf и параметров частью общедоступного API, но на самом деле он явно помечен как "приватный" внутри исходного кода - даже не экспортирован для ссылок. Это заставляет меня сомневаться в том, чтобы просто получить к нему прямой доступ без особого изучения.
В общем, нужен хороший формат хеша, который может хранить scrypt, и реализация, которая предоставляет базовый алгоритм kdf и выбора параметров. В настоящее время я работаю над этим для passlib, но он не привлек к себе большого внимания:(
Просто вкратце - все эти инструкции сайта в порядке, я бы просто использовал пустую строку в качестве содержимого файла и знал о дополнительных издержках и проблемах.
Обе эти ссылки совершенно неверны. Не гадите с encrypt
а также decrypt
: просто используйте hash
KDF не выставляется напрямую, но hash
достаточно близко (На самом деле, мне кажется, что это даже лучше, потому что это смешивает наполнение бутерброда PBKDF2.)
Этот пример кода работает как с python2.7, так и с python3.2. Он использует PyCrypto, passlib и py-scrypt, но требует только py-scrypt.
Вы захотите использовать функцию сравнения с постоянным временем, например passlib.utils.consteq
смягчить временные атаки.
Вы также хотите тщательно выбирать параметры. Значения по умолчанию logN=14,r=8,p=1 означают 1 "раунд" с использованием 16 МБ памяти. На сервере вы, вероятно, хотите что-то большее, например, 10,8,8 - меньше ОЗУ, больше ЦП. Вы должны рассчитать время на вашем оборудовании под ожидаемой нагрузкой.