SHA-256 хешування Python — hashlib та приклади коду

·DevOps Engineer & Python Automation Specialist·ПеревіреноMaria Santos·Опубліковано

Використовуйте безкоштовний SHA-256 Hash Generator прямо в браузері — без встановлення.

Спробувати SHA-256 Hash Generator онлайн →

Кожен конвеєр розгортання, який мені доводилося будувати, врешті-решт потребував перевірки контрольної суми файлу, підпису вебхук-запиту або визначення ключа кешу. SHA-256 хешування в Python за допомогою вбудованого модуля hashlib вирішує всі ці завдання — і він уже встановлений. hashlib.sha256() використовує реалізацію OpenSSL у CPython, тому він швидкий та сумісний з FIPS без додаткового налаштування. Для швидкого разового хешу без написання коду скористайтесь онлайн-генератором SHA-256 хешів — результат з'явиться миттєво. Усі приклади розраховані на Python 3.9+.

  • hashlib.sha256(data).hexdigest() — стандартний спосіб хешування байтів: входить до stdlib, реалізований через OpenSSL.
  • Рядки необхідно спочатку закодувати у байти: hashlib.sha256("text".encode("utf-8")).
  • Для контрольних сум файлів передавайте дані порціями через .update() — ніколи не зчитуйте великий файл цілком у пам'ять.
  • HMAC-SHA256 потребує модуля hmac: hmac.new(key, msg, hashlib.sha256) — SHA-256 сам по собі не підтримує ключ.

Що таке SHA-256 хешування?

SHA-256 (Secure Hash Algorithm, 256-бітний) приймає вхідні дані довільної довжини та виробляє фіксований 256-бітний (32-байтний) дайджест. Однакові вхідні дані завжди дають однаковий результат, але навіть зміна одного біта у вхідних даних призводить до повністю іншого хешу — ця властивість називається лавинним ефектом. SHA-256 належить до родини SHA-2, стандартизованої NIST, і є основою відбитків TLS-сертифікатів, ідентифікаторів комітів Git, заголовків блоків Bitcoin та перевірки цілісності файлів. Алгоритм використовує конструкцію Меркля-Дамгора з 64 раундами стиснення для отримання 256-бітного виводу.

Before · text
After · text
deployment-v4.2.1
a1f7c3d8e9b2...27ae41e4649b (64 hex chars)

Наведений вище hex-дайджест — стандартне представлення: 64 шістнадцяткових символи, завжди однакової довжини незалежно від того, чи ви хешуєте один байт чи образ цілого диска.

hashlib.sha256() — підхід через стандартну бібліотеку

Модуль hashlib постачається з кожною інсталяцією Python — жодного pip install не потрібно. Викличте hashlib.sha256() з аргументом типу bytes для створення об'єкта хешу, а потім отримайте результат через .hexdigest() (шістнадцятковий рядок) або .digest() (необроблені байти). Назва функції пишеться малими літерами: sha256, а не SHA256.

Python 3.9+ — мінімальний SHA-256 хеш
import hashlib

# Хешування рядка байтів безпосередньо
digest = hashlib.sha256(b"deployment-v4.2.1").hexdigest()
print(digest)
# a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db

Найпоширеніша помилка при роботі з hashlib.sha256() — передача str замість bytes. Рядки Python є Unicode, а хеш-функції працюють з необробленими байтами. Перед хешуванням необхідно викликати .encode("utf-8"). Це спотикає майже всіх при першому знайомстві.

Python 3.9+ — хешування рядка
import hashlib

# Рядки необхідно закодувати у байти перед хешуванням
config_key = "redis://cache.internal:6379/0"
digest = hashlib.sha256(config_key.encode("utf-8")).hexdigest()
print(digest)
# 7d3f8c2a1b9e4f5d6c8a7b3e2f1d9c4a5b8e7f6d3c2a1b9e4f5d6c8a7b3e2f1d

Метод .update() дозволяє передавати дані покроково. Виклик h.update(a); h.update(b) еквівалентний hashlib.sha256(a + b). Саме так хешуються файли порціями без завантаження всього вмісту в пам'ять.

Python 3.9+ — покрокове хешування через update()
import hashlib

h = hashlib.sha256()
h.update(b"request_id=req_7f3a91bc")
h.update(b"&timestamp=1741614120")
h.update(b"&amount=4999")
print(h.hexdigest())
# Еквівалентно hashlib.sha256(b"request_id=req_7f3a91bc&timestamp=1741614120&amount=4999").hexdigest()
Примітка:.digest() повертає необроблені 32 байти. .hexdigest() повертає 64-символьний шістнадцятковий рядок. Використовуйте .digest() при передачі результату в HMAC, Base64-кодування або бінарні протоколи. Використовуйте .hexdigest() для журналювання, стовпців бази даних і порівняння контрольних сум.

HMAC-SHA256 — хешування з ключем через модуль hmac

SHA-256 сам по собі не підтримує секретний ключ — будь-хто з тими самими вхідними даними може обчислити той самий хеш. Якщо потрібно підтвердити, що повідомлення надійшло від конкретного відправника (верифікація вебхуків, підпис API-запитів, автентифікація токенів), вам потрібен HMAC. Модуль hmac входить до стандартної бібліотеки Python і вбудовує ключ у процес хешування так, що лише той, хто має ключ, може створити або перевірити однаковий дайджест.

Python 3.9+ — базовий HMAC-SHA256
import hmac
import hashlib

# Верифікація підпису вебхука
secret_key = b"whsec_9f3a7b2e1d4c8a5b"
payload = b'{"event":"invoice.paid","invoice_id":"inv_8d2c","amount":14900}'

signature = hmac.new(secret_key, payload, hashlib.sha256).hexdigest()
print(signature)
# 64-символьний hex HMAC-SHA256 дайджест

Для перевірки вхідного HMAC потрібно використовувати hmac.compare_digest() замість оператора ==. Оператор рівності вразливий до атак за часом — він перериває порівняння на першому невідповідному байті, і зловмисник може вимірювати час відповіді, щоб вгадати правильний підпис байт за байтом. compare_digest() виконується за постійний час незалежно від місця невідповідності.

Python 3.9+ — верифікація підпису вебхука
import hmac
import hashlib

def verify_webhook(payload: bytes, received_sig: str, secret: bytes) -> bool:
    """Перевіряє підпис вебхука за допомогою порівняння за постійним часом."""
    expected = hmac.new(secret, payload, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, received_sig)

# Симуляція верифікації вебхука у стилі Stripe
incoming_payload = b'{"event":"payment.completed","amount":4999}'
incoming_signature = "a1b2c3d4e5f6..."  # з заголовка X-Signature
webhook_secret = b"whsec_9f3a7b2e1d4c"

if verify_webhook(incoming_payload, incoming_signature, webhook_secret):
    print("Підпис дійсний — обробляємо подію")
else:
    print("Підпис не збігається — відхиляємо запит")

Підпис API-запитів з HMAC-SHA256

Підпис API-запитів слідує тому самому принципу: побудуйте канонічний рядок із компонентів запиту (метод, шлях, мітка часу, хеш тіла) та підпишіть його секретним ключем. AWS Signature V4, Stripe і GitHub webhooks використовують варіації цього шаблону.

Python 3.9+ — підпис API-запиту за допомогою HMAC-SHA256
import hmac
import hashlib
import time

def sign_request(method: str, path: str, body: bytes, secret: bytes) -> str:
    """Створює HMAC-SHA256 підпис для API-запиту."""
    timestamp = str(int(time.time()))
    body_hash = hashlib.sha256(body).hexdigest()

    # Канонічний рядок: метод + шлях + мітка часу + хеш тіла
    canonical = f"{method}\n{path}\n{timestamp}\n{body_hash}"
    signature = hmac.new(secret, canonical.encode("utf-8"), hashlib.sha256).hexdigest()

    return f"ts={timestamp},sig={signature}"

# Використання
api_secret = b"sk_live_9f3a7b2e1d4c8a5b6e7f"
request_body = b'{"customer_id":"cust_4f2a","plan":"enterprise"}'
auth_header = sign_request("POST", "/api/v2/subscriptions", request_body, api_secret)
print(f"Authorization: HMAC-SHA256 {auth_header}")
# Authorization: HMAC-SHA256 ts=1741614120,sig=7d3f8c2a...

HMAC-SHA256 у кодуванні Base64

Деякі API (AWS Signature V4, різні платіжні шлюзи) очікують результат HMAC у вигляді рядка Base64, а не шістнадцяткового. Різниця: hex використовує 64 символи, Base64 — 44 символи для того самого 32-байтного дайджесту.

Python 3.9+ — HMAC-SHA256 у кодуванні Base64
import hmac
import hashlib
import base64

secret = b"webhook_secret_9f3a"
message = b"POST /api/v2/events 1741614120"

# Вивід у hex: 64 символи
hex_sig = hmac.new(secret, message, hashlib.sha256).hexdigest()
print(f"Hex:    {hex_sig}")

# Вивід у Base64: 44 символи (коротше, поширено у HTTP-заголовках)
raw_sig = hmac.new(secret, message, hashlib.sha256).digest()
b64_sig = base64.b64encode(raw_sig).decode("ascii")
print(f"Base64: {b64_sig}")

Хешування datetime, UUID та власних об'єктів

SHA-256 працює з необробленими байтами, тому типи, які не є байтами — datetime, UUID, датакласи, моделі Pydantic — необхідно серіалізувати у байти перед хешуванням. Автоматичного перетворення немає; ви самі обираєте канонічне представлення. Для детермінованого хешування між різними системами завжди використовуйте явне кодування та стабільний формат серіалізації (ISO 8601 для datetime, стандартний рядковий формат для UUID, JSON із сортуванням ключів для словників).

Python 3.9+ — хешування datetime та UUID
import hashlib
import uuid
from datetime import datetime, timezone

# datetime — використовуйте ISO 8601 з явним UTC зміщенням для сумісності
event_time = datetime(2026, 3, 28, 12, 0, 0, tzinfo=timezone.utc)
time_hash = hashlib.sha256(event_time.isoformat().encode("utf-8")).hexdigest()
print(f"datetime hash: {time_hash[:16]}...")

# UUID — хешуємо канонічний рядок (нижній регістр, з дефісами)
record_id = uuid.uuid4()
uuid_hash = hashlib.sha256(str(record_id).encode("utf-8")).hexdigest()
print(f"UUID hash: {uuid_hash[:16]}...")

Для власних об'єктів серіалізуйте їх у канонічне байтове представлення перед хешуванням. JSON із сортуванням ключів добре підходить для об'єктів типу словника:

Python 3.9+ — хешування власного об'єкта
import hashlib
import json
from dataclasses import dataclass, asdict

@dataclass
class Event:
    id: str
    type: str
    amount: int
    timestamp: str

def hash_event(event: Event) -> str:
    """Хешує екземпляр датакласу за допомогою JSON із сортуванням ключів для детермінізму."""
    canonical = json.dumps(asdict(event), sort_keys=True, separators=(",", ":"))
    return hashlib.sha256(canonical.encode("utf-8")).hexdigest()

e = Event(id="evt_4f2a", type="payment.completed", amount=4999, timestamp="2026-03-28T12:00:00Z")
print(hash_event(e))  # стабільний результат між запусками та машинами
Примітка:Завжди сортуйте ключі словника (sort_keys=True) при хешуванні JSON-серіалізованих об'єктів. Порядок вставки у словниках зберігається в Python 3.7+, але може відрізнятися між різними шляхами серіалізації, що призводить до різних хешів для однакових даних.

Контрольна сума SHA-256 файлу — верифікація завантажень та артефактів

Обчислення контрольної суми SHA-256 файлу є одним із найпоширеніших використань алгоритму. Ви зустрічаєте це всюди: на сторінках релізів бінарних файлів Go, wheel-пакетів Python, маніфестів Docker-образів, оновлень прошивок. Головне — читати файл порціями, а не завантажувати його повністю: 2 ГБ ISO-образ не повинен вимагати 2 ГБ оперативної пам'яті лише для його хешування.

Python 3.9+ — контрольна сума SHA-256 файлу (порціями)
import hashlib

def sha256_checksum(filepath: str, chunk_size: int = 8192) -> str:
    """Обчислює SHA-256 хеш файлу, читаючи порціями для економії пам'яті."""
    h = hashlib.sha256()
    with open(filepath, "rb") as f:
        for chunk in iter(lambda: f.read(chunk_size), b""):
            h.update(chunk)
    return h.hexdigest()

# Хешування артефакту релізу
checksum = sha256_checksum("/tmp/release-v4.2.1.tar.gz")
print(f"SHA-256: {checksum}")

У Python 3.11 з'явилась функція hashlib.file_digest(), яка виконує читання порціями всередині і може використовувати оптимізації zero-copy на підтримуваних платформах. Якщо ви працюєте на версії 3.11 або новішій, надавайте перевагу їй над ручним циклом.

Python 3.11+ — hashlib.file_digest()
import hashlib

with open("/tmp/release-v4.2.1.tar.gz", "rb") as f:
    digest = hashlib.file_digest(f, "sha256")

print(digest.hexdigest())

Перевірка завантаженого файлу за відомою контрольною сумою

Python 3.9+ — верифікація контрольної суми
import hashlib
import hmac as hmac_mod  # лише для compare_digest

def verify_checksum(filepath: str, expected_hex: str) -> bool:
    """Верифікує контрольну суму SHA-256 з порівнянням за постійним часом."""
    h = hashlib.sha256()
    with open(filepath, "rb") as f:
        for chunk in iter(lambda: f.read(8192), b""):
            h.update(chunk)
    return hmac_mod.compare_digest(h.hexdigest(), expected_hex.lower())

# Верифікація артефакту релізу
expected = "a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db"
if verify_checksum("/tmp/release-v4.2.1.tar.gz", expected):
    print("Контрольна сума збігається — файл цілий")
else:
    print("Контрольна сума не збігається — файл може бути пошкоджений або підмінений")
Примітка:Завжди використовуйте hmac.compare_digest() для порівняння контрольних сум, навіть якщо секретного ключа немає. Порівняння за постійним часом запобігає витоку інформації через вимірювання часу. Оператор == функціонально коректний, але небезпечний у контекстах, пов'язаних із безпекою.

SHA-256 з кодуванням Base64

Деякі протоколи очікують SHA-256 дайджест у вигляді рядка Base64, а не шістнадцяткового. HTTP-заголовки на кшталт Content-Digest та Integrity (Subresource Integrity у браузерах) використовують Base64, а JWT-підписи кодуються у Base64url. Важливо: Base64 кодується з необроблених байтів .digest(), а не з шістнадцяткового рядка.

Python 3.9+ — SHA-256 у кодуванні Base64
import hashlib
import base64

data = b"integrity check payload"

# Правильно: Base64 із необроблених байтів (32 байти → 44 символи Base64)
raw_digest = hashlib.sha256(data).digest()
b64_digest = base64.b64encode(raw_digest).decode("ascii")
print(f"sha256-{b64_digest}")
# sha256-<44 символи>

# Неправильно: Base64 із шістнадцяткового рядка (64 ASCII байти → 88 символів Base64 — вдвічі більше)
hex_digest = hashlib.sha256(data).hexdigest()
wrong = base64.b64encode(hex_digest.encode()).decode()
print(f"Wrong length: {len(wrong)} chars")  # 88 — не те, чого очікують API
Попередження:Кодування шістнадцяткового рядка у Base64 замість необроблених байтів — поширена помилка, яка дає вивід удвічі більшої довжини. API відхилять його, а повідомлення про помилку зазвичай не дає жодних підказок про причину. Завжди викликайте .digest(), а не .hexdigest(), перед Base64-кодуванням.

Довідник hashlib.sha256()

Конструктор та методи об'єкта SHA-256 хешу:

Параметр / Метод
Тип
Опис
data (позиційний)
bytes
Початкові дані для хешування — еквівалентно виклику update(data) одразу після створення об'єкта
.update(data)
bytes
Передає додаткові байти до стану хешу — можна викликати кілька разів для покрокового введення
.digest()
→ bytes
Повертає сирий 32-байтний бінарний дайджест — використовуйте для HMAC, бінарних протоколів, Base64-кодування
.hexdigest()
→ str
Повертає 64-символьний рядок у нижньому регістрі шістнадцяткового формату — стандартне представлення для контрольних сум
.copy()
→ hash object
Повертає копію поточного стану хешу — дозволяє розгалужувати дайджест без повторного хешування з початку
hashlib.sha256()
конструктор
Створює новий об'єкт SHA-256, реалізований через OpenSSL у CPython — usedfips=True у версії 3.9+ обмежує алгоритми до схвалених FIPS

Параметри hmac.new() для хешування з ключем:

Параметр
Тип
Опис
key
bytes
Секретний ключ — має бути bytes, не str
msg
bytes | None
Початкове повідомлення для автентифікації — за замовчуванням None, можна викликати update() пізніше
digestmod
str | callable
Алгоритм хешування: передайте hashlib.sha256 або рядок "sha256"

Бібліотека cryptography — альтернативний SHA-256 API

Пакет cryptography надає інший API для SHA-256 через свої hazmat-примітиви. Я рідко звертаюся до нього, коли потрібен лише хеш — hashlib простіший і не має зовнішніх залежностей. Але якщо ваш проект вже використовує cryptography для TLS, X.509 або симетричного шифрування, використання його хеш-API тримає все під однією бібліотекою та забезпечує єдину обробку помилок.

Python 3.9+ — SHA-256 з бібліотекою cryptography
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.backends import default_backend

digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
digest.update(b"deployment-v4.2.1")
result = digest.finalize()  # необроблені 32 байти

print(result.hex())  # 64-символьний hex рядок
# a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db
Попередження:Бібліотека cryptography потребує pip install cryptography. Об'єкт хешу є одноразовим: повторний виклик .finalize() спричинює AlreadyFinalized. Використовуйте .copy() перед фіналізацією, якщо потрібно розгалужити стан хешу.

Хешування даних із файлу та відповіді API

Два сценарії виникають постійно: хешування файлу на диску для верифікації артефакту релізу та хешування тіла HTTP-відповіді для використання як ключа кешу або перевірки вебхука.

Читання файлу → обчислення SHA-256 → порівняння

Python 3.9+ — хешування резервної копії конфігурації з обробкою помилок
import hashlib
import sys

def hash_file_safe(filepath: str) -> str | None:
    """Хешує файл з належною обробкою помилок."""
    try:
        h = hashlib.sha256()
        with open(filepath, "rb") as f:
            for chunk in iter(lambda: f.read(16384), b""):
                h.update(chunk)
        return h.hexdigest()
    except FileNotFoundError:
        print(f"Помилка: {filepath} не знайдено", file=sys.stderr)
        return None
    except PermissionError:
        print(f"Помилка: немає права читання для {filepath}", file=sys.stderr)
        return None

result = hash_file_safe("/etc/nginx/nginx.conf")
if result:
    print(f"SHA-256: {result}")

HTTP-відповідь → хешування тіла для ключа кешу

Python 3.9+ — хешування відповіді API
import hashlib
import urllib.request
import json

def fetch_and_hash(url: str) -> tuple[dict, str]:
    """Отримує JSON з API та повертає і дані, і їхній SHA-256 хеш."""
    try:
        with urllib.request.urlopen(url, timeout=10) as resp:
            body = resp.read()
            content_hash = hashlib.sha256(body).hexdigest()
            data = json.loads(body)
            return data, content_hash
    except urllib.error.URLError as exc:
        raise ConnectionError(f"Не вдалося отримати {url}: {exc}") from exc

# Ключ кешу на основі вмісту відповіді
data, digest = fetch_and_hash("https://api.exchange.internal/v2/rates")
print(f"Response hash: {digest[:16]}...")
print(f"EUR/USD: {data.get('rates', {}).get('EUR', 'N/A')}")

Для швидкої разової перевірки SHA-256 генератор ToolDeck працює повністю у вашому браузері — жодного коду не потрібно.

SHA-256 хешування в командному рядку

Іноді під час інциденту або розгортання потрібен швидкий хеш прямо в терміналі. Модуль hashlib у Python не має вбудованої CLI-підкоманди (на відміну від python3 -m json.tool), але можна скористатися однорядником або системними інструментами.

bash — хешування рядка з командного рядка
# Python однорядник
echo -n "deployment-v4.2.1" | python3 -c "import hashlib,sys; print(hashlib.sha256(sys.stdin.buffer.read()).hexdigest())"

# macOS / BSD
echo -n "deployment-v4.2.1" | shasum -a 256

# Linux (coreutils)
echo -n "deployment-v4.2.1" | sha256sum

# OpenSSL (крос-платформенний)
echo -n "deployment-v4.2.1" | openssl dgst -sha256
bash — хешування файлу
# Хешування архіву релізу
sha256sum release-v4.2.1.tar.gz
# або
openssl dgst -sha256 release-v4.2.1.tar.gz

# Перевірка за відомою контрольною сумою
echo "a8f5f167f44f4964e6c998dee827110c release-v4.2.1.tar.gz" | sha256sum -c -
# release-v4.2.1.tar.gz: OK
Примітка:Завжди використовуйте echo -n (без завершального символу нового рядка) при хешуванні рядків у командному рядку. Звичайний echo додає \n, що змінює хеш. Це найпоширеніша причина, чому люди отримують різні хеші в Python і в оболонці.

Висока продуктивність — hashlib з OpenSSL та pycryptodome

У CPython hashlib.sha256() вже делегує роботу C-реалізації OpenSSL, тому він швидкий — як правило, 500+ МБ/с на сучасному залізі.

Якщо SHA-256 хешування з'являється у вашому профайлері — наприклад, ви обчислюєте контрольні суми для тисяч файлів у CI-конвеєрі або хешуєте кожне тіло запиту у високонавантаженому API-шлюзі — існують два варіанти: оптимізувати схему викликів hashlib або перейти на pycryptodome для уніфікованого криптографічного API, що охоплює також SHA-3 і BLAKE2:

bash — встановлення pycryptodome
pip install pycryptodome
Python 3.9+ — SHA-256 з pycryptodome
from Crypto.Hash import SHA256

h = SHA256.new()
h.update(b"deployment-v4.2.1")
print(h.hexdigest())
# a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db

Для паралельного хешування файлів із високою пропускною здатністю більший виграш дає зменшення накладних витрат Python через більші розміри порцій та багатопотоковість:

Python 3.9+ — пакетне хешування файлів з hashlib
import hashlib
import os
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor

def hash_file(path: Path) -> tuple[str, str]:
    """Хешує один файл і повертає (шлях, hex дайджест)."""
    h = hashlib.sha256()
    with open(path, "rb") as f:
        for chunk in iter(lambda: f.read(65536), b""):  # порції по 64 КБ
            h.update(chunk)
    return str(path), h.hexdigest()

def hash_directory(directory: str, pattern: str = "*.tar.gz") -> dict[str, str]:
    """Хешує всі відповідні файли паралельно за допомогою потоків."""
    files = list(Path(directory).glob(pattern))
    results = {}
    with ThreadPoolExecutor(max_workers=os.cpu_count()) as pool:
        for path, digest in pool.map(hash_file, files):
            results[path] = digest
    return results

# Паралельне хешування всіх артефактів релізу
checksums = hash_directory("/var/releases", "*.tar.gz")
for path, digest in checksums.items():
    print(f"{digest}  {path}")

Використання порцій по 64 КБ замість 8 КБ скорочує кількість викликів Python→C у 8 разів. Потоки добре підходять тут, оскільки GIL знімається під час хешування на рівні C — вузьким місцем є дисковий ввід-вивід, а не процесор.

Кольоровий вивід у терміналі

Бібліотека rich корисна, коли потрібно верифікувати пакет файлів і відобразити таблицю зі статусом pass/fail для кожного файлу замість простого виводу hex-рядків.

bash — встановлення rich
pip install rich
Python 3.9+ — кольоровий вивід для верифікації хешів
import hashlib
from pathlib import Path
from rich.console import Console
from rich.table import Table

console = Console()

def hash_and_display(files: list[str], expected: dict[str, str]) -> None:
    """Хешує файли та відображає результати з кольоровою верифікацією."""
    table = Table(title="SHA-256 Verification")
    table.add_column("File", style="cyan")
    table.add_column("SHA-256", style="dim", max_width=20)
    table.add_column("Status")

    for filepath in files:
        h = hashlib.sha256()
        with open(filepath, "rb") as f:
            for chunk in iter(lambda: f.read(8192), b""):
                h.update(chunk)
        digest = h.hexdigest()

        name = Path(filepath).name
        status = "[green]✓ OK[/green]" if expected.get(name) == digest else "[red]✗ MISMATCH[/red]"
        table.add_row(name, f"{digest[:16]}...", status)

    console.print(table)

# Використання
expected_checksums = {
    "api-gateway-v3.1.tar.gz": "a8f5f167f44f4964...",
    "worker-v3.1.tar.gz": "7d3f8c2a1b9e4f5d...",
}
hash_and_display(
    ["/var/releases/api-gateway-v3.1.tar.gz", "/var/releases/worker-v3.1.tar.gz"],
    expected_checksums,
)
Примітка:Кольоровий вивід rich призначений лише для відображення в терміналі. Не записуйте ANSI-коди у лог-файли або відповіді API — вимкніть їх за допомогою console.print(data, highlight=False) або перенаправте у файл через Console(file=open(...)).

Робота з великими файлами

Порційний шаблон з .update() обробляє файли будь-якого розміру з постійним використанням пам'яті. Для дуже великих файлів (багатогігабайтні образи дисків, резервні копії баз даних) основне питання зміщується від пам'яті до зворотного зв'язку з користувачем — хешування 10 ГБ зі швидкістю 500 МБ/с займає 20 секунд, і мовчання протягом цього часу турбує.

Python 3.9+ — хешування великих файлів з відображенням прогресу
import hashlib
import os

def sha256_with_progress(filepath: str) -> str:
    """Хешує великий файл з відображенням прогресу у stderr."""
    file_size = os.path.getsize(filepath)
    h = hashlib.sha256()
    bytes_read = 0

    with open(filepath, "rb") as f:
        while chunk := f.read(1 << 20):  # порції по 1 МБ
            h.update(chunk)
            bytes_read += len(chunk)
            pct = (bytes_read / file_size) * 100
            print(f"\r  Хешування: {pct:.1f}% ({bytes_read >> 20} МБ / {file_size >> 20} МБ)",
                  end="", flush=True)

    print()  # новий рядок після прогресу
    return h.hexdigest()

digest = sha256_with_progress("/mnt/backups/db-snapshot-2026-03.sql.gz")
print(f"SHA-256: {digest}")

NDJSON / JSON Lines — хешування кожного запису окремо

Python 3.9+ — хешування окремих записів у потоці NDJSON
import hashlib
import json

def hash_ndjson_records(filepath: str) -> dict[str, str]:
    """Хешує кожен JSON-запис у файлі NDJSON для дедуплікації."""
    seen = {}
    with open(filepath, "r", encoding="utf-8") as f:
        for line_num, line in enumerate(f, 1):
            line = line.strip()
            if not line:
                continue
            try:
                record = json.loads(line)
                # Нормалізація перед хешуванням: сортуємо ключі для детермінізму
                canonical = json.dumps(record, sort_keys=True, separators=(",", ":"))
                digest = hashlib.sha256(canonical.encode("utf-8")).hexdigest()

                if digest in seen:
                    print(f"Рядок {line_num}: дублікат рядка {seen[digest]}")
                else:
                    seen[digest] = line_num
            except json.JSONDecodeError:
                print(f"Рядок {line_num}: некоректний JSON, пропущено")

    print(f"Оброблено {line_num} рядків, {len(seen)} унікальних записів")
    return seen

hash_ndjson_records("telemetry-events-2026-03.ndjson")
Примітка:Перейдіть від одноразового виклику hashlib.sha256(data) до порційного циклу з .update(), коли файли перевищують 50–100 МБ. Нижче цього порогу читання всього файлу через f.read() цілком прийнятне — використання пам'яті буде приблизно рівним розміру файлу.

Поширені помилки

Передача str замість bytes до hashlib.sha256()

Проблема: hashlib.sha256('text') викидає TypeError: Unicode-objects must be encoded before hashing. Функція вимагає bytes, а не str.

Рішення: Спочатку закодуйте рядок: hashlib.sha256('text'.encode('utf-8')). Або використовуйте літерал b'' для жорстко заданих значень.

Before · Python
After · Python
import hashlib
digest = hashlib.sha256("deployment-v4.2.1").hexdigest()
# TypeError: Unicode-objects must be encoded before hashing
import hashlib
digest = hashlib.sha256("deployment-v4.2.1".encode("utf-8")).hexdigest()
# Працює — повертає 64-символьний hex рядок
Використання == замість hmac.compare_digest() для верифікації підписів

Проблема: Оператор == перериває порівняння на першому невідповідному байті. Зловмисник може вимірювати час відповіді для вгадування правильного підпису байт за байтом.

Рішення: Використовуйте hmac.compare_digest() для всіх порівнянь, пов'язаних із безпекою — він виконується за постійний час незалежно від місця невідповідності.

Before · Python
After · Python
received_sig = request.headers["X-Signature"]
expected_sig = hmac.new(key, body, hashlib.sha256).hexdigest()
if received_sig == expected_sig:  # вразливо до атак за часом
    process_webhook(body)
received_sig = request.headers["X-Signature"]
expected_sig = hmac.new(key, body, hashlib.sha256).hexdigest()
if hmac.compare_digest(received_sig, expected_sig):  # постійний час
    process_webhook(body)
Base64-кодування шістнадцяткового рядка замість необроблених байтів

Проблема: base64.b64encode(digest.hexdigest().encode()) дає 88-символьний рядок — вдвічі більший за очікувані 44 символи. API, що очікують Base64-кодований SHA-256, відхиляють його.

Рішення: Викликайте .digest() (необроблені байти) перед Base64-кодуванням, а не .hexdigest() (шістнадцятковий рядок).

Before · Python
After · Python
import hashlib, base64
hex_str = hashlib.sha256(data).hexdigest()
b64 = base64.b64encode(hex_str.encode())  # 88 символів — неправильно!
import hashlib, base64
raw = hashlib.sha256(data).digest()
b64 = base64.b64encode(raw)  # 44 символи — правильно
Завантаження великого файлу цілком у пам'ять перед хешуванням

Проблема: hashlib.sha256(open('large.iso', 'rb').read()) завантажує весь файл у пам'ять. Файл 4 ГБ вимагає 4 ГБ оперативної пам'яті лише для обчислення хешу.

Рішення: Читайте файл порціями у циклі з .update(). Використання пам'яті залишається постійним незалежно від розміру файлу.

Before · Python
After · Python
import hashlib
# Завантажує весь файл 4 ГБ у пам'ять
digest = hashlib.sha256(open("disk.iso", "rb").read()).hexdigest()
import hashlib
h = hashlib.sha256()
with open("disk.iso", "rb") as f:
    for chunk in iter(lambda: f.read(8192), b""):
        h.update(chunk)
digest = h.hexdigest()  # постійне використання пам'яті

hashlib vs hmac vs альтернативи — швидке порівняння

Метод
Вивід
З ключем
Швидкість
Стрімінг файлів
Потребує встановлення
Власні типи
hashlib.sha256()
hex / bytes
Швидко (C/OpenSSL)
✓ через update()
Ні (stdlib)
Ручне encode()
hmac.new()
hex / bytes
Швидко (C/OpenSSL)
✓ через update()
Ні (stdlib)
Ручне encode()
hashlib.file_digest()
hex / bytes
Швидко (zero-copy)
✓ (вбудовано)
Ні (3.11+)
Ручне encode()
cryptography hashes.SHA256()
bytes
Швидко (OpenSSL)
✓ через update()
pip install
Ручне encode()
subprocess openssl dgst
hex string
✗ / ✓
Повільніше (fork)
✓ (рівень ОС)
System openssl
Ручне encode()
pyhashcat / custom
varies
GPU-прискорення
pip install
Ручне encode()

Для простого хешування — контрольні суми, ключі кешу, ідентифікація вмісту — залишайтеся з hashlib.sha256(). Переходьте до hmac.new() у той момент, коли потрібен секретний ключ (вебхуки, підписи API, автентифікація токенів). Звертайтеся до бібліотеки cryptography лише якщо ваш проект вже використовує її для шифрування або TLS — додавати C-розширення лише заради хешування надлишково, коли hashlib вже реалізований через OpenSSL.

Чи можна розшифрувати SHA-256? — Хешування vs шифрування

Коротка відповідь: ні. SHA-256 — це одностороння функція. Алгоритм розроблений як незворотний — ви не можете відновити вихідні дані з 256-бітного дайджесту. Це не обмеження реалізації; це математична властивість хеш-функції. Простір виводу у 256 бітів є астрономічно великим (2256 можливих значень), а функція втрачає інформацію під час 64 раундів стиснення.

Зловмисники можуть спробувати атаки грубою силою або за словником проти слабких вхідних даних (поширені паролі, короткі рядки), але для будь-яких вхідних даних із достатньою ентропією — ключів API, випадкових токенів, вмісту файлів — відновлення SHA-256 є обчислювально неможливим на сучасному залізі. Якщо вам потрібне оборотне перетворення, використовуйте симетричне шифрування:

Python 3.9+ — шифрування vs хешування
# Хешування — одностороннє, не можна відновити оригінал
import hashlib
digest = hashlib.sha256(b"secret-config-value").hexdigest()
# Немає способу отримати "secret-config-value" з дайджесту

# Шифрування — двостороннє, можна розшифрувати з ключем
from cryptography.fernet import Fernet
key = Fernet.generate_key()
cipher = Fernet(key)
encrypted = cipher.encrypt(b"secret-config-value")
decrypted = cipher.decrypt(encrypted)
print(decrypted)  # b"secret-config-value" — оригінал відновлено

Для швидкого способу згенерувати SHA-256 хеш без встановлення пакетів онлайн-інструмент працює повністю у вашому браузері.

Як перевірити, чи є рядок коректним SHA-256 хешем у Python

Коректний SHA-256 hex-дайджест — це рівно 64 шістнадцяткових символи (0-9, a-f, A-F). Швидка перевірка перед обробкою ненадійних вхідних даних запобігає заплутаним помилкам на пізніших етапах.

Python 3.9+ — валідація формату SHA-256
import re

def is_sha256_hex(value: str) -> bool:
    """Перевіряє, чи відповідає рядок формату SHA-256 hex-дайджесту."""
    return bool(re.fullmatch(r"[a-fA-F0-9]{64}", value))

# Тестові випадки
print(is_sha256_hex("e3b0c44298fc1c149afbf4c8996fb924"
                     "27ae41e4649b934ca495991b7852b855"))  # True — SHA-256 порожнього рядка
print(is_sha256_hex("e3b0c44298fc1c14"))                   # False — занадто короткий
print(is_sha256_hex("zzzz" * 16))                          # False — некоректні hex-символи
Примітка:Це перевіряє лише формат, а не те, чи хеш обчислений з якихось конкретних вхідних даних. Немає способу визначити, чи є 64-символьний шістнадцятковий рядок "справжнім" SHA-256 дайджестом або просто випадковими hex-даними — вивід SHA-256 є неможливо відрізнити від випадкових даних за задумом.

Часті запитання

Як хешувати рядок за допомогою SHA-256 у Python?

Викличте hashlib.sha256() з рядком, закодованим у байти. Рядки в Python є Unicode, а хеш-функції працюють з необробленими байтами, тому спочатку потрібно викликати .encode("utf-8"). Метод .hexdigest() повертає знайомий 64-символьний шістнадцятковий рядок.

Python
import hashlib

api_key = "sk_live_9f3a7b2e1d4c"
digest = hashlib.sha256(api_key.encode("utf-8")).hexdigest()
print(digest)
# e3b7c4a1f8d2...64 hex characters

Чи можна розшифрувати SHA-256 хеш назад до початкового тексту?

Ні. SHA-256 — це одностороння функція: вона перетворює вхідні дані довільної довжини на фіксований 256-бітний вивід і безповоротно втрачає вихідну структуру. Математичного зворотного перетворення не існує. Зловмисники можуть спробувати грубу силу або атаки за допомогою райдужних таблиць проти слабких вхідних даних (короткі паролі, поширені слова), але для будь-якого вхідного значення з достатньою ентропією відновлення SHA-256 є обчислювально неможливим. Якщо вам потрібне оборотне перетворення, використовуйте шифрування (AES-GCM, Fernet), а не хешування.

У чому різниця між .digest() та .hexdigest()?

.digest() повертає необроблені 32 байти хешу як об'єкт bytes. .hexdigest() повертає ті самі дані, закодовані як 64-символьний рядок у нижньому регістрі шістнадцяткового формату. Використовуйте .digest(), коли потрібен бінарний вивід — для передачі в HMAC, Base64-кодування або запис у бінарні протоколи. Використовуйте .hexdigest(), коли потрібен читабельний рядок для журналювання, збереження в базі даних або порівняння контрольних сум.

Python
import hashlib

h = hashlib.sha256(b"deployment-v4.2.1")
print(len(h.digest()))     # 32 (bytes)
print(len(h.hexdigest()))  # 64 (hex characters)

Як обчислити контрольну суму SHA-256 файлу в Python?

Відкрийте файл у бінарному режимі та передавайте його до хешера порціями через .update(). У Python 3.11+ використовуйте hashlib.file_digest() для ще простішого API. Ніколи не викликайте f.read() для великих файлів — це завантажить весь файл у пам'ять.

Python
import hashlib

def sha256_file(path: str) -> str:
    h = hashlib.sha256()
    with open(path, "rb") as f:
        for chunk in iter(lambda: f.read(8192), b""):
            h.update(chunk)
    return h.hexdigest()

print(sha256_file("release-v4.2.1.tar.gz"))

Як створити підпис HMAC-SHA256 у Python?

Використовуйте модуль hmac з hashlib.sha256 як digestmod. Передайте секретний ключ і повідомлення у вигляді байтів. Результат — це хеш із ключем, який підтверджує як цілісність, так і автентичність: отримувач повинен мати той самий ключ для перевірки.

Python
import hmac
import hashlib

secret = b"webhook_secret_9f3a"
payload = b'{"event":"payment.completed","amount":4999}'
signature = hmac.new(secret, payload, hashlib.sha256).hexdigest()
print(signature)  # 64-char hex HMAC

Як перевірити, чи є рядок коректним SHA-256 hex-дайджестом?

SHA-256 hex-дайджест — це рівно 64 шістнадцяткових символи. Використовуйте регулярний вираз або просту перевірку довжини та символів. Підхід із регулярним виразом є найбільш читабельним.

Python
import re

def is_sha256(s: str) -> bool:
    return bool(re.fullmatch(r"[a-fA-F0-9]{64}", s))

print(is_sha256("e3b0c44298fc1c149afbf4c8996fb924"
                 "27ae41e4649b934ca495991b7852b855"))  # True
print(is_sha256("not-a-hash"))  # False

Пов'язані інструменти

DV
Dmitri VolkovDevOps Engineer & Python Automation Specialist

Dmitri is a DevOps engineer who relies on Python as his primary scripting and automation language. He builds internal tooling, CI/CD pipelines, and infrastructure automation scripts that run in production across distributed teams. He writes about the Python standard library, subprocess management, file processing, encoding utilities, and the practical shell-adjacent Python that DevOps engineers use every day.

MS
Maria SantosТехнічний рецензент

Maria is a backend developer specialising in Python and API integration. She has broad experience with data pipelines, serialisation formats, and building reliable server-side services. She is an active member of the Python community and enjoys writing practical, example-driven guides that help developers solve real problems without unnecessary theory.