Python: уроки, справочник и задачи

Модуль hashlib: хеш-функции в Python

Раздел: Модули и библиотеки Python · Обновлено 31.10.2026

Python hashlib - модуль стандартной библиотеки, который вычисляет хеши данных алгоритмами SHA-256, SHA-512, SHA-3, BLAKE2, MD5 и другими. В статье показано, как получить хеш строки и большого файла, чем отличаются алгоритмы, как правильно хранить пароли и проверять подлинность сообщений через HMAC.

Python Hashlib
Фото: Frettie / CC BY 3.0, Wikimedia Commons
Содержание статьи
  1. Что такое хеш и зачем он нужен
  2. Хеш строки
    1. Пошаговое хеширование через update
  3. Хеш файла
  4. Какой алгоритм выбрать
  5. Хранение паролей
  6. Подпись сообщений через HMAC
  7. Частые вопросы
    1. Можно ли расшифровать хеш SHA-256 или MD5?
    2. Почему хеш одной строки отличается в разных программах?
    3. Подходит ли встроенная функция hash() вместо hashlib?
    4. Чем хеширование отличается от шифрования?

Что такое хеш и зачем он нужен

Хеш-функция превращает данные любого размера в строку фиксированной длины. Одинаковые данные всегда дают одинаковый хеш, а изменение даже одного байта меняет результат до неузнаваемости. Восстановить исходные данные по хешу нельзя.

На практике хеши используют для нескольких задач:

Хеш строки

Хеш-функции работают с байтами, а не со строками. Строку сначала кодируют методом encode(), по умолчанию в UTF-8. Если передать str напрямую, Python выбросит TypeError: Strings must be encoded before hashing.

import hashlib

data = "Hello, World!".encode("utf-8")
h = hashlib.sha256(data)
print(h.hexdigest())
# dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f
print(len(h.digest()))   # 32 байта
print(hashlib.md5("привет".encode()).hexdigest())
# 608333adc72f545078ede3aad71bfe74

hexdigest() возвращает хеш строкой из шестнадцатеричных символов, digest() возвращает сырые байты. Кодировку важно выбирать одинаковую при каждом вычислении: одна и та же кириллическая строка в UTF-8 и cp1251 даст разные хеши. Подробнее о кодировках рассказано в статье про кодировку строк.

Пошаговое хеширование через update

Объект хеша можно наполнять частями методом update(). Результат будет таким же, как при передаче всех данных сразу. Метод copy() сохраняет промежуточное состояние, если нужно получить хеш нескольких вариантов с общим началом.

h = hashlib.sha256()
h.update(b"Hello, ")
h.update(b"World!")
print(h.hexdigest() == hashlib.sha256(b"Hello, World!").hexdigest())  # True

Хеш файла

Файл открывают в двоичном режиме "rb". В Python 3.11 появилась функция hashlib.file_digest(), которая сама читает файл блоками и не загружает его в память целиком.

import hashlib

with open("python-3.12.exe", "rb") as f:
    print(hashlib.file_digest(f, "sha256").hexdigest())

Для старых версий Python тот же результат дает цикл с update(). Размер блока 64-1024 КБ хорошо подходит для большинства дисков, а приемы чтения больших файлов разобраны в отдельной статье о чтении больших файлов.

def sha256_of(path, chunk=1024 * 1024):
    h = hashlib.sha256()
    with open(path, "rb") as f:
        while block := f.read(chunk):
            h.update(block)
    return h.hexdigest()

expected = "..."  # контрольная сумма с сайта загрузки
print(sha256_of("python-3.12.exe") == expected)

Какой алгоритм выбрать

Набор алгоритмов, доступных на любой платформе, хранится в hashlib.algorithms_guaranteed. Дополнительные алгоритмы из OpenSSL перечислены в algorithms_available, их создают по имени через hashlib.new("имя").

АлгоритмДлина хеша, битПрименение
md5128только контрольные суммы и дубликаты, для защиты непригоден
sha1160устарел, найдены коллизии; встречается в старых системах и Git
sha256256универсальный выбор: подписи, контрольные суммы, токены
sha512512то же, на 64-битных процессорах часто быстрее sha256
sha3_256256стандарт SHA-3 на другой математической основе
blake2bдо 512быстрый, поддерживает ключ и произвольную длину результата

MD5 и SHA-1 нельзя использовать там, где важна защита от подделки: для них умеют подбирать разные данные с одинаковым хешем. Для поиска дубликатов они подходят, а в сборках Python с режимом FIPS их вызывают с аргументом usedforsecurity=False.

short = hashlib.blake2b(b"data", digest_size=8).hexdigest()
print(short)   # 2e6c49b7ae486fa8, короткий идентификатор

Хранение паролей

Обычный SHA-256 для паролей не годится. Он считается очень быстро, и перебор миллиардов вариантов на видеокарте занимает минуты. Кроме того, без соли одинаковые пароли дают одинаковые хеши. Для паролей в hashlib есть медленные функции с солью: scrypt() и pbkdf2_hmac().

import hashlib, hmac, os

def hash_password(password: str) -> tuple[bytes, bytes]:
    salt = os.urandom(16)
    key = hashlib.scrypt(password.encode(), salt=salt, n=2**14, r=8, p=1)
    return salt, key

def check_password(password: str, salt: bytes, key: bytes) -> bool:
    new = hashlib.scrypt(password.encode(), salt=salt, n=2**14, r=8, p=1)
    return hmac.compare_digest(new, key)

salt, key = hash_password("qwerty123")
print(check_password("qwerty123", salt, key))  # True

Соль генерируется случайно для каждого пароля и хранится рядом с хешем в открытом виде. Сравнение через hmac.compare_digest() занимает одинаковое время независимо от того, где найдено различие, это защищает от атак по времени. Для pbkdf2_hmac("sha256", ...) рекомендуют сотни тысяч итераций.

Подпись сообщений через HMAC

Хеш подтверждает, что данные не повреждены, но не доказывает, кто их отправил: злоумышленник может изменить сообщение и пересчитать хеш. HMAC добавляет секретный ключ, известный только отправителю и получателю. Так подписывают вебхуки платежных систем и API-запросы.

import hmac

secret = b"server-secret"
body = b'{"order": 42, "status": "paid"}'
signature = hmac.new(secret, body, "sha256").hexdigest()

received = signature  # подпись из заголовка запроса
print(hmac.compare_digest(signature, received))  # True

Модуль hmac тоже входит в стандартную библиотеку. Полный список функций hashlib и их параметров есть в документации Python.

Частые вопросы

Ответы на вопросы, которые чаще всего задают о hashlib.

Можно ли расшифровать хеш SHA-256 или MD5?

Нет, хеширование необратимо. Онлайн-сервисы "расшифровки" ищут хеш в базах заранее посчитанных значений популярных строк, поэтому простые пароли находятся, а случайные данные нет.

Почему хеш одной строки отличается в разных программах?

Обычно виновата кодировка или невидимые символы: перевод строки в конце, пробел, BOM. Хеш считается от байтов, и любое расхождение в них дает другой результат.

Подходит ли встроенная функция hash() вместо hashlib?

Нет. hash() нужна для словарей и множеств, для строк ее значение меняется при каждом запуске интерпретатора из-за случайной соли. Для сохранения и сравнения между запусками используйте hashlib.

Чем хеширование отличается от шифрования?

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