crypt — Функция проверки паролей Unix


Данный модуль реализует интерфейс к подпрограмме crypt(3), которая представляет собой одностороннюю хеш-функцию, основанную на модифицированном алгоритме DES; см. справочную страницу Unix для получения дополнительной информации. Возможное использование включает хранение хэшированных паролей, чтобы вы могли проверять пароли без сохранения фактического пароля, или пытаться взломать пароли Unix с помощью словаря.

Обратите внимание, что поведение этого модуля зависит от фактической реализации подпрограммы crypt(3) в работающей системе. Поэтому любые расширения, доступные в текущей реализации, также будут доступны в этом модуле.

Доступность: Unix. Недоступно в VxWorks.

Методы хеширования

Добавлено в версии 3.3.

Модуль crypt определяет список методов хеширования (не все методы доступны на всех платформах):

crypt.METHOD_SHA512

Метод Modular Crypt Format с солью из 16 символов и хэшем из 86 символов на основе хеш-функции SHA-512. Это самый сильный метод.

crypt.METHOD_SHA256

Другой метод Modular Crypt Format с 16-символьной солью и 43-символьным хешем на основе хеш-функции SHA-256.

crypt.METHOD_BLOWFISH

Другой метод Modular Crypt Format с 22-символьной солью и 31-символьным хешем на основе шифра Blowfish.

Добавлено в версии 3.7.

crypt.METHOD_MD5

Другой метод Modular Crypt Format с 8-символьной солью и 22-символьным хешем на основе хеш-функции MD5.

crypt.METHOD_CRYPT

Традиционный метод с 2 символами соли и 13 символами хэша. Это самый слабый метод.

Атрибуты модуля

Добавлено в версии 3.3.

crypt.methods

Список доступных алгоритмов хеширования паролей в виде объектов crypt.METHOD_*. Данный список отсортирован от самого сильного к самому слабому.

Функции модуля

Модуль crypt определяет следующие функции:

crypt.crypt(word, salt=None)

word обычно представляет собой пароль пользователя, введенный в командной строке или в графическом интерфейсе. Необязательный salt — это либо строка, возвращаемая из mksalt(), либо одно из значений crypt.METHOD_* (хотя не все они могут быть доступны на всех платформах), либо полный зашифрованный пароль, включая соль, возвращаемая этой функцией. Если salt не указан, будет использоваться самый надежный метод (как возвращается methods()).

Проверка пароля обычно выполняется путём передачи открытого текста пароля в виде word и полных результатов предыдущего вызова crypt(), которые должны совпадать с результатами этого вызова.

salt (случайная строка из 2 или 16 символов, возможно с префиксом $digit$ для указания метода), который будет использоваться для нарушения алгоритма шифрования. Символы в salt должны быть в множестве [./a-zA-Z0-9], за исключением Modular Crypt Format, который имеет префикс $digit$.

Возвращает хешированный пароль в виде строки, состоящей из символов того же алфавита, что и соль.

Поскольку несколько расширений crypt(3) допускают разные значения с разными размерами в salt, рекомендуется использовать полный зашифрованный пароль в качестве соли при проверке пароля.

Изменено в версии 3.3: Принимайте значения crypt.METHOD_* в дополнение к строкам для salt.

crypt.mksalt(method=None, *, rounds=None)

Возвращает случайно сгенерированную соль указанного метода. Если method не указан, используется самый надежный из доступных методов, возвращённый methods().

Возвращаемое значение представляет собой строку, подходящую для передачи в качестве аргумента salt в crypt().

rounds указывает количество раундов для METHOD_SHA256, METHOD_SHA512 и METHOD_BLOWFISH. Для METHOD_SHA256 и METHOD_SHA512 это должно быть целое число между 1000 и 999_999_999, по умолчанию 5000. Для METHOD_BLOWFISH это должна быть степень двойки между 16 (24) и 2_147_483_648 (231), по умолчанию 4096 (212).

Добавлено в версии 3.3.

Изменено в версии 3.7: Добавлен параметр rounds.

Примеры

Простой пример, иллюстрирующий типичное использование (операция сравнения с постоянным временем необходима для ограничения воздействия атак по времени. Для этой цели подходит hmac.compare_digest()):

import pwd
import crypt
import getpass
from hmac import compare_digest as compare_hash

def login():
    username = input('Python login: ')
    cryptedpasswd = pwd.getpwnam(username)[1]
    if cryptedpasswd:
        if cryptedpasswd == 'x' or cryptedpasswd == '*':
            raise ValueError('no support for shadow passwords')
        cleartext = getpass.getpass()
        return compare_hash(crypt.crypt(cleartext, cryptedpasswd), cryptedpasswd)
    else:
        return True

Сгенерировать хэш пароля самым надежным из доступных методов и сравнить его с оригиналом:

import crypt
from hmac import compare_digest as compare_hash

hashed = crypt.crypt(plaintext)
if not compare_hash(hashed, crypt.crypt(plaintext, hashed)):
    raise ValueError("hashed version doesn't validate against original")