PythonでSHA-256 — hashlibガイド
無料の SHA-256ハッシュ生成ツール をブラウザで直接使用 — インストール不要。
SHA-256ハッシュ生成ツール をオンラインで試す →デプロイメントパイプラインを構築するとき、ファイルのチェックサム検証、Webhookペイロードへの署名、またはキャッシュキーのフィンガープリント計算が必要になる場面は必ずあります。PythonのSHA-256ハッシュは標準ライブラリの hashlib モジュールですべてのケースを処理できます — しかも既にインストール済みです。 hashlib.sha256() はCPythonでOpenSSLの実装をラップしているため、高速でかつFIPS準拠です。コードを書かずに手軽にハッシュを計算したい場合は、 オンラインSHA-256ハッシュジェネレーター で即座に結果が得られます。すべてのサンプルはPython 3.9以降を対象としています。
- ✓hashlib.sha256(data).hexdigest()がbytesをハッシュする標準的な方法 — stdlibに含まれOpenSSLを使用。
- ✓文字列は事前にbytesにエンコードが必要: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バイト)のダイジェストを生成します。同じ入力は常に同じ出力を生成しますが、入力の1ビットが変化するだけで全く異なるハッシュが生成されます — この特性はアバランシェ効果と呼ばれます。SHA-256はNISTによって標準化されたSHA-2ファミリーの一部であり、TLS証明書のフィンガープリント、GitのコミットID、Bitcoinのブロックヘッダー、ファイル整合性検証の基盤となっています。このアルゴリズムはMerkle-Damgård構造を使用し、64回の圧縮ラウンドで256ビットの出力を生成します。
deployment-v4.2.1
a1f7c3d8e9b2...27ae41e4649b (64文字の16進数)
上記の16進数ダイジェストが標準的な表現形式です — 1バイトをハッシュしても、ディスクイメージ全体をハッシュしても、常に同じ長さの64文字の16進数になります。
hashlib.sha256() — 標準ライブラリを使ったアプローチ
hashlib モジュールはすべてのPythonインストールに同梱されています — pip install は不要です。 bytes 引数を指定して hashlib.sha256() を呼び出してハッシュオブジェクトを生成し、 .hexdigest() (16進数文字列)または .digest() (生のバイト列)で結果を取得します。関数名は小文字の sha256であり、SHA256ではありません。
import hashlib # バイト文字列を直接ハッシュ digest = hashlib.sha256(b"deployment-v4.2.1").hexdigest() print(digest) # a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db
hashlib.sha256() でよくある間違いは、 bytes ではなく str を渡してしまうことです。Pythonの文字列はUnicodeであり、ハッシュ関数は生のバイト列を対象とします。ハッシュの前に .encode("utf-8") を呼び出す必要があります。初めて使う場合はほぼ全員がこの点でつまずきます。
import hashlib
# ハッシュ前に文字列をbytesにエンコードする必要がある
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) と同等です。これがファイル全体をメモリに読み込まずにチャンク単位でハッシュする方法です。
import hashlib h = hashlib.sha256() h.update(b"request_id=req_7f3a91bc") h.update(b"×tamp=1741614120") h.update(b"&amount=4999") print(h.hexdigest()) # hashlib.sha256(b"request_id=req_7f3a91bc×tamp=1741614120&amount=4999").hexdigest()と同等
.digest() は生の32バイトを返します。 .hexdigest() は64文字の16進数文字列を返します。 HMAC入力、Base64エンコード、バイナリプロトコルへの投入には .digest() を使用してください。 ログ記録、データベースカラム、チェックサム比較には .hexdigest() を使用してください。HMAC-SHA256 — hmacモジュールを使った鍵付きハッシュ
SHA-256単体では秘密鍵の概念がありません — 同じ入力があれば誰でも同じハッシュを計算できます。メッセージが特定の送信者から来たことを証明する必要がある場合(Webhook検証、APIリクエスト署名、トークン認証)はHMACが必要です。 hmac モジュールはPythonの標準ライブラリに含まれており、鍵をハッシュ処理に組み込むため、鍵を持つ者だけが同じダイジェストを生成・検証できます。
import hmac
import hashlib
# Webhook署名の検証
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文字の16進数HMAC-SHA256ダイジェスト受信したHMACの検証には == 演算子ではなく hmac.compare_digest() を使用する必要があります。等値演算子は最初に不一致のバイトで短絡評価します。攻撃者はレスポンスタイムを計測して署名を1バイトずつ推測できます。 compare_digest() は不一致の位置に関係なく一定時間で実行されます。
import hmac
import hashlib
def verify_webhook(payload: bytes, received_sig: str, secret: bytes) -> bool:
"""定時間比較によるWebhook署名の検証。"""
expected = hmac.new(secret, payload, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, received_sig)
# Stripeスタイルのwebhook検証をシミュレート
incoming_payload = b'{"event":"payment.completed","amount":4999}'
incoming_signature = "a1b2c3d4e5f6..." # X-SignatureヘッダーからHMAC署名を取得
webhook_secret = b"whsec_9f3a7b2e1d4c"
if verify_webhook(incoming_payload, incoming_signature, webhook_secret):
print("署名有効 — イベントを処理します")
else:
print("署名不一致 — リクエストを拒否します")HMAC-SHA256によるリクエスト署名
APIリクエスト署名も同じ原理に従います:リクエストの構成要素(メソッド、パス、タイムスタンプ、ボディハッシュ)から正規文字列を構築し、秘密鍵で署名します。AWS Signature V4、Stripe、GitHubのWebhookはすべてこのパターンのバリエーションを使用しています。
import hmac
import hashlib
import time
def sign_request(method: str, path: str, body: bytes, secret: bytes) -> str:
"""APIリクエスト用のHMAC-SHA256署名を生成。"""
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...Base64エンコードされたHMAC-SHA256
一部のAPI(AWS Signature V4、各種ペイメントゲートウェイ)はHMACの結果を16進数ではなくBase64エンコードされた文字列として期待します。違い:16進数は64文字、Base64は同じ32バイトダイジェストに対して44文字を使用します。
import hmac
import hashlib
import base64
secret = b"webhook_secret_9f3a"
message = b"POST /api/v2/events 1741614120"
# 16進数出力: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は生のバイト列を対象とするため、bytesでない型 — datetime、 UUID、データクラス、Pydanticモデル — はハッシュ前にバイト列にシリアライズする必要があります。自動変換はありません。正規表現を選択します。 システム間で決定的なハッシュを行うには、明示的なエンコーディングと安定したシリアライズ形式を使用してください(datetimeにはISO 8601、UUIDには標準文字列形式、dictには辞書順ソートJSON)。
import hashlib
import uuid
from datetime import datetime, timezone
# datetime — 移植性のために明示的なUTCオフセットを使ったISO 8601形式
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ハッシュ: {time_hash[:16]}...")
# UUID — 標準文字列形式(小文字、ハイフン付き)をハッシュ
record_id = uuid.uuid4()
uuid_hash = hashlib.sha256(str(record_id).encode("utf-8")).hexdigest()
print(f"UUIDハッシュ: {uuid_hash[:16]}...")カスタムオブジェクトの場合、ハッシュ前に正規バイト列表現にシリアライズします。 辞書風オブジェクトにはソートキーを使ったJSONが適しています:
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)。dictの挿入順序はPython 3.7以降で保持されますが、シリアライズ経路によって異なる場合があり、同一データに対して異なるハッシュが生成される可能性があります。SHA-256ファイルチェックサム — ダウンロードとアーティファクトの検証
ファイルのSHA-256チェックサムを計算することはこのアルゴリズムの最も一般的な用途の一つです。Goバイナリのリリースページ、Pythonのwheelファイル、Dockerイメージマニフェスト、ファームウェアアップデートなど至る所で使われています。重要なのはファイル全体を一度に読み込まずにチャンク単位で読み込むことです — 2 GBのISOイメージのハッシュ計算のためだけに2 GBのRAMを必要とすべきではありません。
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() が追加されました。内部でチャンク読み込みを行い、対応プラットフォームではゼロコピー最適化が使われる場合があります。3.11以降を使用している場合は手動ループより優先して使用してください。
import hashlib
with open("/tmp/release-v4.2.1.tar.gz", "rb") as f:
digest = hashlib.file_digest(f, "sha256")
print(digest.hexdigest())既知のチェックサムに対してダウンロードファイルを検証
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() を使用してください。定時間比較はタイミングベースの情報漏洩を防ぎます。 == 演算子は機能上は問題ありませんが、セキュリティ上重要なコンテキストでは安全ではありません。Base64エンコードを使ったSHA-256
一部のプロトコルはSHA-256ダイジェストを16進数ではなくBase64文字列として期待します。 HTTPヘッダーの Content-Digest や Integrity (ブラウザのサブリソース整合性)はBase64を使用し、JWT署名はBase64urlエンコードされています。 コツは16進数文字列ではなく生の .digest() バイト列を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文字>
# 誤った方法:16進数文字列のBase64(64 ASCIIバイト → 88文字のBase64 — サイズが倍になる)
hex_digest = hashlib.sha256(data).hexdigest()
wrong = base64.b64encode(hex_digest.encode()).decode()
print(f"誤った長さ: {len(wrong)}文字") # 88 — APIが期待する値ではない.hexdigest()ではなく.digest()を呼び出してください。hashlib.sha256() リファレンス
SHA-256ハッシュオブジェクトのコンストラクタとメソッド:
鍵付きハッシュ用の hmac.new() パラメータ:
cryptographyライブラリ — 代替のSHA-256 API
cryptography パッケージはhazmatプリミティブを通じてSHA-256の異なるAPIを提供します。単純なハッシュが必要な場合はほとんど使用しません — hashlib の方がシンプルで外部依存がありません。しかし、プロジェクトがすでにTLS、X.509、または対称暗号化のために cryptography に依存している場合、そのハッシュAPIを使用することでライブラリを一本化し、一貫したエラーハンドリングが可能になります。
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文字の16進数文字列 # a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db
cryptographyライブラリには pip install cryptographyが必要です。ハッシュオブジェクトは使い捨てです: .finalize()を2回呼び出すと AlreadyFinalizedが発生します。ハッシュ状態を分岐させる必要がある場合はファイナライズ前に .copy()を使用してください。ファイルとAPIレスポンスのデータをハッシュ
常によく出てくる2つのシナリオがあります:リリースアーティファクトを検証するためのディスク上のファイルのハッシュ化と、キャッシュキーとして使用するかWebhookを検証するためのHTTPレスポンスボディのハッシュ化です。
ファイル読み込み → SHA-256計算 → 比較
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レスポンス → ボディをハッシュしてキャッシュキーを生成
import hashlib
import urllib.request
import json
def fetch_and_hash(url: str) -> tuple[dict, str]:
"""APIからJSONを取得し、データとその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"レスポンスハッシュ: {digest[:16]}...")
print(f"EUR/USD: {data.get('rates', {}).get('EUR', 'N/A')}")手軽に試したい場合は、 ToolDeckのSHA-256ジェネレーター がブラウザ上で完全に動作します — コード不要です。
コマンドラインでのSHA-256ハッシュ
インシデント対応やデプロイ中にターミナルで手軽にハッシュが必要な場合があります。 Pythonの hashlib モジュールには組み込みのCLIサブコマンドがありません( python3 -m json.toolとは異なり)、 ただしワンライナーまたはシステムツールを使用できます。
# 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
# リリースtar ballをハッシュ 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とシェルでハッシュのGit値が異なる原因の大半がこれです。高パフォーマンスの代替案 — hashlibとOpenSSL、pycryptodome
CPythonでは、 hashlib.sha256() はすでにOpenSSLのC実装に委譲しているため高速です — 最新のハードウェアでは通常500 MB/s以上です。
SHA-256ハッシュがプロファイラに出てくる場合 — たとえばCIパイプラインで数千のファイルのチェックサムを計算したり、高スループットAPIゲートウェイで全リクエストボディをハッシュする場合 — 2つの選択肢があります: hashlib の呼び出しパターンを最適化するか、SHA-3やBLAKE2もカバーする統合暗号APIの pycryptodome に切り替えることです:
pip install pycryptodome
from Crypto.Hash import SHA256 h = SHA256.new() h.update(b"deployment-v4.2.1") print(h.hexdigest()) # a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db
高スループットの並列ファイルハッシュでは、チャンクサイズを大きくしてスレッドを使用することでPythonのオーバーヘッドを削減できます:
import hashlib
import os
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
def hash_file(path: Path) -> tuple[str, str]:
"""単一ファイルをハッシュし(パス, 16進数ダイジェスト)を返す。"""
h = hashlib.sha256()
with open(path, "rb") as f:
for chunk in iter(lambda: f.read(65536), b""): # 64 KBチャンク
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}")8 KBの代わりに64 KBチャンクを使用することでPythonからCへの呼び出し回数が8分の1になります。C レベルのハッシュ処理中はGILが解放されるため、スレッドが有効です — ボトルネックはCPUではなくディスクI/Oです。
ターミナルへのシンタックスハイライト表示
rich ライブラリは、大量のファイルを検証する際に、生の16進数が流れるのではなくファイルごとの合否ステータスを示すテーブルを表示したい場合に役立ちます。
pip install rich
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 検証")
table.add_column("ファイル", style="cyan")
table.add_column("SHA-256", style="dim", max_width=20)
table.add_column("ステータス")
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]✗ 不一致[/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,
)console.print(data, highlight=False) でエスケープコードを除去するか、Console(file=open(...))でファイルにリダイレクトしてください。大きなファイルの処理
チャンク化された.update() パターンはあらゆるサイズのファイルを一定のメモリ使用量で処理します。非常に大きなファイル(複数GBのディスクイメージ、データベースバックアップ)では、懸念事項がメモリからユーザーへのフィードバックに移ります — 500 MB/sで10 GBをハッシュするには20秒かかり、その間の沈黙は不安を生じさせます。
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 MBチャンク
h.update(chunk)
bytes_read += len(chunk)
pct = (bytes_read / file_size) * 100
print(f"\r ハッシュ中: {pct:.1f}% ({bytes_read >> 20} MB / {file_size >> 20} MB)",
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 — レコードごとに個別にハッシュ
import hashlib
import json
def hash_ndjson_records(filepath: str) -> dict[str, str]:
"""重複排除のためNDJSONファイルの各JSONレコードをハッシュ。"""
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()ループに切り替えてください。 それ以下のサイズであればf.read()でファイル全体を読み込んでも問題ありません — メモリ使用量はファイルサイズとほぼ同等です。よくある間違い
問題: hashlib.sha256('text')はTypeError: Unicode-objects must be encoded before hashingを発生させます。この関数はstrではなくbytesを要求します。
解決策: 最初に文字列をエンコードしてください:hashlib.sha256('text'.encode('utf-8'))。ハードコードされた値にはb''リテラルを使用します。
import hashlib
digest = hashlib.sha256("deployment-v4.2.1").hexdigest()
# TypeError: Unicode-objects must be encoded before hashingimport hashlib
digest = hashlib.sha256("deployment-v4.2.1".encode("utf-8")).hexdigest()
# 動作する — 64文字の16進数文字列を返す問題: ==演算子は最初に不一致のバイトで短絡評価します。攻撃者はレスポンスタイムを計測して正しい署名を1バイトずつ推測できます。
解決策: セキュリティ上重要なすべての比較にhmac.compare_digest()を使用してください — 不一致の位置に関係なく一定時間で実行されます。
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.b64encode(digest.hexdigest().encode())は88文字の文字列を生成します — 期待される44文字の2倍です。Base64エンコードされたSHA-256を期待するAPIはこれを拒否します。
解決策: Base64エンコード前に.hexdigest()(16進数文字列)ではなく.digest()(生バイト)を呼び出してください。
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 GBのファイルはハッシュ計算だけで4 GBのRAMを必要とします。
解決策: ループと.update()でチャンク単位に読み込んでください。ファイルサイズに関係なくメモリ使用量は一定です。
import hashlib
# 4 GBのファイル全体をメモリに読み込む
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() を使用してください。秘密鍵が必要になった瞬間(Webhook、API署名、トークン認証)は hmac.new() に切り替えてください。 cryptography ライブラリは、プロジェクトがすでに暗号化やTLSのために使用している場合のみ選択してください — hashlibがすでにOpenSSLに支援されているのに、ハッシュのためだけにC拡張の依存関係を追加するのは過剰です。
SHA-256は復号できるか — ハッシュと暗号化の違い
端的に言うと、できません。SHA-256は一方向関数です。このアルゴリズムは不可逆であるよう設計されています — 256ビットダイジェストから元の入力を再構築することはできません。これは実装上の制限ではなく、ハッシュ関数の数学的な特性です。256ビットの出力空間は天文学的に大きく(2256通りの値)、この関数は64回の圧縮ラウンドで情報を破棄します。
攻撃者は弱い入力(一般的なパスワード、短い文字列)に対してブルートフォースや辞書攻撃を試みることができますが、適切なエントロピーを持つ入力 — APIキー、ランダムトークン、ファイルコンテンツ — に対してSHA-256を逆算することは現在のハードウェアでは計算上不可能です。可逆変換が必要な場合は対称暗号化を使用してください:
# ハッシュ — 一方向、元の値を復元不可 import hashlib digest = hashlib.sha256(b"secret-config-value").hexdigest() # digestから"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ハッシュを生成したい場合は、オンラインツールがブラウザ上で完全に動作します。
PythonでSHA-256ハッシュ形式を検証する方法
有効なSHA-256の16進数ダイジェストはちょうど64文字の16進数(0-9、a-f、A-F)です。信頼できない入力を処理する前にクイック検証を行うことで、後続の処理での不明瞭なエラーを防ぎます。
import re
def is_sha256_hex(value: str) -> bool:
"""文字列がSHA-256 16進数ダイジェスト形式に一致するか確認。"""
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 — 無効な16進数文字よくある質問
PythonでSHA-256文字列ハッシュを計算するには?
hashlib.sha256()にバイト列にエンコードした文字列を渡します。Pythonの文字列はUnicodeですが、ハッシュ関数は生のバイト列を対象とするため、事前に.encode("utf-8")を呼び出す必要があります。.hexdigest()メソッドが64文字の16進数文字列を返します。
import hashlib
api_key = "sk_live_9f3a7b2e1d4c"
digest = hashlib.sha256(api_key.encode("utf-8")).hexdigest()
print(digest)
# e3b7c4a1f8d2...64文字の16進数SHA-256ハッシュを元のテキストに復号できますか?
できません。SHA-256は一方向関数です — 任意長の入力を固定256ビット出力にマッピングし、その過程で情報を破棄します。数学的な逆関数は存在しません。攻撃者は弱い入力(短いパスワード、一般的な単語)に対してブルートフォースやレインボーテーブル攻撃を試みることができますが、十分なエントロピーを持つ入力に対してSHA-256を逆算することは計算上不可能です。可逆変換が必要な場合はハッシュではなく暗号化(AES-GCM、Fernet)を使用してください。
.digest()と.hexdigest()の違いは何ですか?
.digest()はハッシュの生の32バイトをbytesオブジェクトとして返します。.hexdigest()は同じデータを64文字の小文字16進数文字列としてエンコードして返します。バイナリ出力が必要な場合 — HMACへの入力、Base64エンコード、バイナリプロトコルへの書き込み — は.digest()を使用します。ログ記録、データベース保存、チェックサム比較で人間が読める文字列が必要な場合は.hexdigest()を使用します。
import hashlib h = hashlib.sha256(b"deployment-v4.2.1") print(len(h.digest())) # 32 (バイト) print(len(h.hexdigest())) # 64 (16進数文字)
PythonでファイルのSHA-256チェックサムを計算するには?
ファイルをバイナリモードで開き、.update()でチャンク単位にハッシャーに投入します。Python 3.11以降ではhashlib.file_digest()がさらにシンプルなAPIを提供します。大きなファイルでf.read()を呼び出すとファイル全体がメモリに読み込まれるため避けてください。
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"))PythonでHMAC-SHA256署名を作成するには?
digestmodにhashlib.sha256を指定してhmacモジュールを使用します。秘密鍵とメッセージをbytesとして渡します。結果は整合性と真正性の両方を証明する鍵付きハッシュです — 受信者は同じ鍵を持っていないと検証できません。
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文字の16進数HMAC文字列が有効なSHA-256 16進数ダイジェストかどうかを検証するには?
SHA-256の16進数ダイジェストはちょうど64文字の16進数です。正規表現または長さと文字のチェックを使用します。正規表現のアプローチが最も読みやすいです。
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関連ツール
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.
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.