SHA-256 en Python — Guide hashlib + Exemples de code
Utilisez le Générateur de Hash SHA-256 gratuit directement dans votre navigateur — sans installation.
Essayer Générateur de Hash SHA-256 en ligne →Chaque pipeline de déploiement que j'ai construit finit par avoir besoin de vérifier la somme de contrôle d'un fichier, signer un payload webhook ou générer une empreinte de clé de cache. Le hachage SHA-256 en Python avec le module intégré hashlib couvre tous ces cas — et il est déjà installé. hashlib.sha256() délègue à l'implémentation C d'OpenSSL sous CPython, ce qui le rend rapide et conforme FIPS d'emblée. Pour un hachage rapide sans écrire de code, le générateur SHA-256 en ligne donne le résultat instantanément. Tous les exemples ciblent Python 3.9+.
- ✓hashlib.sha256(data).hexdigest() est la méthode standard pour hacher des bytes — inclus dans la stdlib, basé sur OpenSSL.
- ✓Les chaînes doivent d'abord être encodées en bytes : hashlib.sha256("texte".encode("utf-8")).
- ✓Pour les sommes de contrôle de fichiers, alimente par morceaux via .update() — ne lis jamais un gros fichier entièrement en mémoire.
- ✓HMAC-SHA256 nécessite le module hmac : hmac.new(key, msg, hashlib.sha256) — SHA-256 seul n'a pas de clé.
Qu'est-ce que le hachage SHA-256 ?
SHA-256 (Secure Hash Algorithm, 256 bits) prend une entrée de longueur arbitraire et produit un condensat fixe de 256 bits (32 octets). La même entrée produit toujours la même sortie, mais même un changement d'un seul bit dans l'entrée produit un hachage complètement différent — cette propriété s'appelle l'effet avalanche. SHA-256 fait partie de la famille SHA-2, standardisée par le NIST, et est au cœur des empreintes de certificats TLS, des identifiants de commits Git, des en-têtes de blocs Bitcoin et de la vérification d'intégrité des fichiers. L'algorithme utilise une construction Merkle-Damgård avec 64 tours de compression pour produire sa sortie de 256 bits.
deployment-v4.2.1
a1f7c3d8e9b2...27ae41e4649b (64 caractères hex)
Le condensat hexadécimal ci-dessus est la représentation standard — 64 caractères hexadécimaux, toujours de la même longueur que tu haches un seul octet ou une image disque entière.
hashlib.sha256() — L'approche bibliothèque standard
Le module hashlib est livré avec chaque installation Python — pas de pip install nécessaire. Appelle hashlib.sha256() avec un argument de type bytes pour créer un objet de hachage, puis récupère le résultat avec .hexdigest() (chaîne hex) ou .digest() (octets bruts). Le nom de la fonction est en minuscules : sha256, pas SHA256.
import hashlib # Hacher une chaîne d'octets directement digest = hashlib.sha256(b"deployment-v4.2.1").hexdigest() print(digest) # a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db
L'erreur la plus courante avec hashlib.sha256() est de passer un str à la place de bytes. Les chaînes Python sont Unicode, et les fonctions de hachage opèrent sur des octets bruts. Tu dois appeler .encode("utf-8") avant de hacher. C'est un piège que tout le monde rencontre la première fois.
import hashlib
# Les chaînes doivent être encodées en bytes avant le hachage
config_key = "redis://cache.internal:6379/0"
digest = hashlib.sha256(config_key.encode("utf-8")).hexdigest()
print(digest)
# 7d3f8c2a1b9e4f5d6c8a7b3e2f1d9c4a5b8e7f6d3c2a1b9e4f5d6c8a7b3e2f1dLa méthode .update() permet d'alimenter les données de manière incrémentale. Appeler h.update(a); h.update(b) est équivalent à hashlib.sha256(a + b). C'est ainsi que tu haches des fichiers par morceaux sans charger tout le contenu en mémoire.
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()) # Équivalent à hashlib.sha256(b"request_id=req_7f3a91bc×tamp=1741614120&amount=4999").hexdigest()
.digest() renvoie les 32 octets bruts. .hexdigest() renvoie une chaîne hexadécimale de 64 caractères. Utilise .digest() pour alimenter HMAC, encoder en Base64 ou travailler avec des protocoles binaires. Utilise .hexdigest() pour les journaux, les colonnes de base de données et la comparaison de sommes de contrôle.HMAC-SHA256 — Hachage avec clé via le module hmac
SHA-256 seul n'a pas de notion de clé secrète — n'importe qui avec la même entrée peut calculer le même hachage. Si tu dois prouver qu'un message provient d'un expéditeur spécifique (vérification de webhook, signature de requête API, authentification par token), tu as besoin de HMAC. Le module hmac fait partie de la bibliothèque standard Python et intègre la clé dans le processus de hachage de sorte que seul quelqu'un avec la clé peut produire ou vérifier le même condensat.
import hmac
import hashlib
# Vérification de signature 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)
# Condensat HMAC-SHA256 hexadécimal de 64 caractèresLa vérification d'un HMAC entrant nécessite hmac.compare_digest() plutôt que l'opérateur ==. L'opérateur d'égalité est vulnérable aux attaques temporelles — il court-circuite au premier octet différent, et un attaquant peut mesurer les temps de réponse pour deviner la signature correcte octet par octet. compare_digest() s'exécute en temps constant quel que soit l'endroit où se produit la différence.
import hmac
import hashlib
def verify_webhook(payload: bytes, received_sig: str, secret: bytes) -> bool:
"""Vérifie une signature webhook par comparaison en temps constant."""
expected = hmac.new(secret, payload, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, received_sig)
# Simulation d'une vérification de webhook style Stripe
incoming_payload = b'{"event":"payment.completed","amount":4999}'
incoming_signature = "a1b2c3d4e5f6..." # depuis l'en-tête X-Signature
webhook_secret = b"whsec_9f3a7b2e1d4c"
if verify_webhook(incoming_payload, incoming_signature, webhook_secret):
print("Signature valide — traiter l'événement")
else:
print("Signature incorrecte — rejeter la requête")Signature de requête HMAC-SHA256
La signature de requêtes API suit le même principe : construire une chaîne canonique à partir des composants de la requête (méthode, chemin, horodatage, hachage du corps) et la signer avec ta clé secrète. AWS Signature V4, Stripe et les webhooks GitHub utilisent tous des variantes de ce modèle.
import hmac
import hashlib
import time
def sign_request(method: str, path: str, body: bytes, secret: bytes) -> str:
"""Crée une signature HMAC-SHA256 pour une requête API."""
timestamp = str(int(time.time()))
body_hash = hashlib.sha256(body).hexdigest()
# Chaîne canonique : méthode + chemin + horodatage + hachage du corps
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}"
# Utilisation
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 encodé en Base64
Certaines APIs (AWS Signature V4, diverses passerelles de paiement) attendent le résultat HMAC sous forme de chaîne encodée en Base64 plutôt qu'en hexadécimal. La différence : hex utilise 64 caractères, Base64 utilise 44 caractères pour les mêmes 32 octets de condensat.
import hmac
import hashlib
import base64
secret = b"webhook_secret_9f3a"
message = b"POST /api/v2/events 1741614120"
# Sortie hex : 64 caractères
hex_sig = hmac.new(secret, message, hashlib.sha256).hexdigest()
print(f"Hex: {hex_sig}")
# Sortie Base64 : 44 caractères (plus court, courant dans les en-têtes HTTP)
raw_sig = hmac.new(secret, message, hashlib.sha256).digest()
b64_sig = base64.b64encode(raw_sig).decode("ascii")
print(f"Base64: {b64_sig}")Hachage de datetime, UUID et objets personnalisés
SHA-256 opère sur des octets bruts, donc les types non-bytes — datetime, UUID, dataclasses, modèles Pydantic — doivent être sérialisés en bytes avant le hachage. Il n'y a pas de conversion automatique ; tu choisis la représentation canonique. Pour un hachage déterministe entre systèmes, utilise toujours un encodage explicite et un format de sérialisation stable (ISO 8601 pour les datetimes, la forme chaîne standard pour les UUIDs, JSON avec clés triées pour les dicts).
import hashlib
import uuid
from datetime import datetime, timezone
# datetime — utiliser ISO 8601 avec décalage UTC explicite pour la portabilité
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 — hacher la forme chaîne canonique (minuscules, avec tirets)
record_id = uuid.uuid4()
uuid_hash = hashlib.sha256(str(record_id).encode("utf-8")).hexdigest()
print(f"UUID hash: {uuid_hash[:16]}...")Pour les objets personnalisés, sérialise vers une représentation bytes canonique avant le hachage. JSON avec clés triées fonctionne bien pour les objets de type dict :
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:
"""Hache une instance de dataclass en utilisant JSON avec clés triées pour le déterminisme."""
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)) # stable entre les exécutions et les machinessort_keys=True) lors du hachage d'objets sérialisés en JSON. L'ordre d'insertion des dicts est préservé en Python 3.7+ mais peut différer selon les chemins de sérialisation, produisant des hachages différents pour des données identiques.Somme de contrôle SHA-256 — Vérifier les téléchargements et artefacts
Calculer une somme de contrôle SHA-256 d'un fichier est l'un des usages les plus courants de l'algorithme. On le voit partout : pages de release pour les binaires Go, fichiers wheel Python, manifestes d'images Docker, mises à jour de firmware. La clé est de lire le fichier par morceaux plutôt que de tout charger d'un coup — une image ISO de 2 Go ne devrait pas nécessiter 2 Go de RAM juste pour la hacher.
import hashlib
def sha256_checksum(filepath: str, chunk_size: int = 8192) -> str:
"""Calcule le hachage SHA-256 d'un fichier, en lisant par morceaux pour économiser la mémoire."""
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()
# Hacher un artefact de release
checksum = sha256_checksum("/tmp/release-v4.2.1.tar.gz")
print(f"SHA-256: {checksum}")Python 3.11 a ajouté hashlib.file_digest() qui effectue la lecture par morceaux en interne et peut utiliser des optimisations zéro copie sur les plateformes supportées. Si tu es sur 3.11 ou ultérieur, préfère-le à la boucle manuelle.
import hashlib
with open("/tmp/release-v4.2.1.tar.gz", "rb") as f:
digest = hashlib.file_digest(f, "sha256")
print(digest.hexdigest())Vérifier un fichier téléchargé contre une somme de contrôle connue
import hashlib
import hmac as hmac_mod # uniquement pour compare_digest
def verify_checksum(filepath: str, expected_hex: str) -> bool:
"""Vérifie la somme de contrôle SHA-256 par comparaison en temps constant."""
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())
# Vérifier un artefact de release
expected = "a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db"
if verify_checksum("/tmp/release-v4.2.1.tar.gz", expected):
print("Somme de contrôle correcte — fichier intact")
else:
print("Somme de contrôle incorrecte — fichier potentiellement corrompu ou altéré")hmac.compare_digest() pour les comparaisons de sommes de contrôle, même quand il n'y a pas de clé secrète. La comparaison en temps constant évite les fuites d'information par mesure du temps. L'opérateur ==fonctionne sur le plan fonctionnel mais n'est pas sûr dans les contextes sensibles à la sécurité.SHA-256 avec encodage Base64
Certains protocoles attendent le condensat SHA-256 sous forme de chaîne Base64 plutôt qu'en hexadécimal. Les en-têtes HTTP comme Content-Digest et Integrity (Subresource Integrity dans les navigateurs) utilisent Base64, et les signatures JWT sont encodées en Base64url. L'astuce est d'encoder en Base64 les octets bruts de .digest(), pas la chaîne hexadécimale.
import hashlib
import base64
data = b"integrity check payload"
# Correct : Base64 des octets bruts (32 octets → 44 caractères Base64)
raw_digest = hashlib.sha256(data).digest()
b64_digest = base64.b64encode(raw_digest).decode("ascii")
print(f"sha256-{b64_digest}")
# sha256-<44 caractères>
# Incorrect : Base64 de la chaîne hex (64 octets ASCII → 88 caractères Base64 — deux fois plus grand)
hex_digest = hashlib.sha256(data).hexdigest()
wrong = base64.b64encode(hex_digest.encode()).decode()
print(f"Longueur incorrecte : {len(wrong)} caractères") # 88 — pas ce qu'attendent les APIs.digest(), pas .hexdigest(), avant l'encodage Base64.Référence hashlib.sha256()
Le constructeur et les méthodes d'un objet de hachage SHA-256 :
Paramètres de hmac.new() pour le hachage avec clé :
La bibliothèque cryptography — Une API SHA-256 alternative
Le package cryptography fournit une API différente pour SHA-256 via ses primitives hazmat. Je l'utilise rarement quand j'ai seulement besoin d'un hachage — hashlib est plus simple et sans dépendance externe. Mais si ton projet dépend déjà de cryptography pour TLS, X.509 ou le chiffrement symétrique, utiliser son API de hachage permet de tout garder sous une seule bibliothèque avec une gestion cohérente des erreurs.
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 octets bruts print(result.hex()) # chaîne hex de 64 caractères # a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db
cryptography nécessite pip install cryptography. L'objet de hachage est à usage unique : appeler .finalize() une deuxième fois lève AlreadyFinalized. Utilise .copy()avant de finaliser si tu dois bifurquer l'état de hachage.Hacher des données depuis un fichier et une réponse API
Deux scénarios reviennent constamment : hacher un fichier sur disque pour vérifier un artefact de release, et hacher le corps d'une réponse HTTP pour l'utiliser comme clé de cache ou vérifier un webhook.
Lire un fichier → Calculer SHA-256 → Comparer
import hashlib
import sys
def hash_file_safe(filepath: str) -> str | None:
"""Hache un fichier avec une gestion des erreurs appropriée."""
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"Erreur : {filepath} introuvable", file=sys.stderr)
return None
except PermissionError:
print(f"Erreur : permission de lecture refusée pour {filepath}", file=sys.stderr)
return None
result = hash_file_safe("/etc/nginx/nginx.conf")
if result:
print(f"SHA-256: {result}")Réponse HTTP → Hacher le corps pour une clé de cache
import hashlib
import urllib.request
import json
def fetch_and_hash(url: str) -> tuple[dict, str]:
"""Récupère du JSON depuis une API et renvoie les données et leur hachage 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"Échec de la récupération de {url}: {exc}") from exc
# Clé de cache basée sur le contenu de la réponse
data, digest = fetch_and_hash("https://api.exchange.internal/v2/rates")
print(f"Hash de la réponse : {digest[:16]}...")
print(f"EUR/USD: {data.get('rates', {}).get('EUR', 'N/A')}")Pour une vérification rapide, le générateur SHA-256 de ToolDeck fonctionne entièrement dans ton navigateur — sans code nécessaire.
Hachage SHA-256 en ligne de commande
Parfois tu as juste besoin d'un hachage rapide dans le terminal pendant un incident ou un déploiement. Le module hashlib de Python n'a pas de sous-commande CLI intégrée (contrairement à python3 -m json.tool), mais tu peux utiliser une commande en une ligne ou les outils système.
# Commande Python en une ligne 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 (multiplateforme) echo -n "deployment-v4.2.1" | openssl dgst -sha256
# Hacher une archive de release sha256sum release-v4.2.1.tar.gz # ou openssl dgst -sha256 release-v4.2.1.tar.gz # Vérifier contre une somme de contrôle connue echo "a8f5f167f44f4964e6c998dee827110c release-v4.2.1.tar.gz" | sha256sum -c - # release-v4.2.1.tar.gz: OK
echo -n (sans saut de ligne final) pour hacher des chaînes en ligne de commande. Un simple echo ajoute un \n, ce qui change le hachage. C'est la première cause de différences de hachages entre Python et le shell.Alternative haute performance — hashlib avec OpenSSL et pycryptodome
Sous CPython, hashlib.sha256() délègue déjà à l'implémentation C d'OpenSSL, donc il est rapide — généralement 500+ Mo/s sur du matériel moderne.
Si le hachage SHA-256 apparaît dans ton profileur — par exemple tu calcules des sommes de contrôle pour des milliers de fichiers dans un pipeline CI ou tu haches chaque corps de requête dans une passerelle API à fort débit — deux options existent : optimiser le schéma d'appel à hashlib, ou passer à pycryptodome pour une API crypto unifiée qui couvre aussi SHA-3 et BLAKE2 :
pip install pycryptodome
from Crypto.Hash import SHA256 h = SHA256.new() h.update(b"deployment-v4.2.1") print(h.hexdigest()) # a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db
Pour le hachage de fichiers parallèle à fort débit, les gains les plus importants viennent de la réduction de la surcharge Python via des tailles de morceaux plus grandes et le threading :
import hashlib
import os
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
def hash_file(path: Path) -> tuple[str, str]:
"""Hache un seul fichier et renvoie (chemin, condensat hex)."""
h = hashlib.sha256()
with open(path, "rb") as f:
for chunk in iter(lambda: f.read(65536), b""): # morceaux de 64 Ko
h.update(chunk)
return str(path), h.hexdigest()
def hash_directory(directory: str, pattern: str = "*.tar.gz") -> dict[str, str]:
"""Hache tous les fichiers correspondants en parallèle avec des threads."""
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
# Hacher tous les artefacts de release en parallèle
checksums = hash_directory("/var/releases", "*.tar.gz")
for path, digest in checksums.items():
print(f"{digest} {path}")Utiliser des morceaux de 64 Ko au lieu de 8 Ko réduit le nombre d'appels Python vers C par 8. Les threads fonctionnent bien ici parce que le GIL est libéré pendant le hachage au niveau C — le goulot d'étranglement est l'I/O disque, pas le CPU.
Sortie terminale avec mise en évidence syntaxique
La bibliothèque rich est utile quand tu dois vérifier un lot de fichiers et vouloir un tableau affichant le statut réussite/échec par fichier plutôt que du hex brut qui défile.
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:
"""Hache les fichiers et affiche les résultats avec une vérification colorée."""
table = Table(title="Vérification SHA-256")
table.add_column("Fichier", style="cyan")
table.add_column("SHA-256", style="dim", max_width=20)
table.add_column("Statut")
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]✗ ERREUR[/red]"
table.add_row(name, f"{digest[:16]}...", status)
console.print(table)
# Utilisation
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) ou redirige vers un fichier avec Console(file=open(...)).Travailler avec de gros fichiers
Le schéma .update() par morceaux gère les fichiers de toute taille avec une utilisation constante de la mémoire. Pour les très gros fichiers (images disque multi-Go, sauvegardes de bases de données), la préoccupation principale passe de la mémoire au retour utilisateur — hacher 10 Go à 500 Mo/s prend quand même 20 secondes, et le silence pendant ce temps inquiète les gens.
import hashlib
import os
def sha256_with_progress(filepath: str) -> str:
"""Hache un gros fichier avec un rapport de progression sur 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): # morceaux de 1 Mo
h.update(chunk)
bytes_read += len(chunk)
pct = (bytes_read / file_size) * 100
print(f"\r Hachage : {pct:.1f}% ({bytes_read >> 20} Mo / {file_size >> 20} Mo)",
end="", flush=True)
print() # saut de ligne après la progression
return h.hexdigest()
digest = sha256_with_progress("/mnt/backups/db-snapshot-2026-03.sql.gz")
print(f"SHA-256: {digest}")NDJSON / JSON Lines — Hacher chaque enregistrement séparément
import hashlib
import json
def hash_ndjson_records(filepath: str) -> dict[str, str]:
"""Hache chaque enregistrement JSON d'un fichier NDJSON pour la déduplication."""
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)
# Normaliser avant le hachage : trier les clés pour une sortie déterministe
canonical = json.dumps(record, sort_keys=True, separators=(",", ":"))
digest = hashlib.sha256(canonical.encode("utf-8")).hexdigest()
if digest in seen:
print(f"Ligne {line_num} : doublon de la ligne {seen[digest]}")
else:
seen[digest] = line_num
except json.JSONDecodeError:
print(f"Ligne {line_num} : JSON invalide, ignoré")
print(f"Traité {line_num} lignes, {len(seen)} enregistrements uniques")
return seen
hash_ndjson_records("telemetry-events-2026-03.ndjson")hashlib.sha256(data) en une passe à la boucle .update() par morceaux quand les fichiers dépassent 50 à 100 Mo. En dessous de ce seuil, lire le fichier entier avec f.read() convient — l'utilisation mémoire sera approximativement égale à la taille du fichier.Erreurs courantes
Problème : hashlib.sha256('texte') lève TypeError: Unicode-objects must be encoded before hashing. La fonction exige des bytes, pas un str.
Solution : Encode la chaîne d'abord : hashlib.sha256('texte'.encode('utf-8')). Ou utilise un littéral b'' pour les valeurs codées en dur.
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()
# Fonctionne — renvoie une chaîne hex de 64 caractèresProblème : L'opérateur == court-circuite au premier octet différent. Un attaquant peut mesurer le temps de réponse pour deviner la signature correcte octet par octet.
Solution : Utilise hmac.compare_digest() pour toutes les comparaisons sensibles à la sécurité — il s'exécute en temps constant quel que soit l'endroit de la différence.
received_sig = request.headers["X-Signature"]
expected_sig = hmac.new(key, body, hashlib.sha256).hexdigest()
if received_sig == expected_sig: # vulnérable aux attaques temporelles
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): # temps constant
process_webhook(body)Problème : base64.b64encode(digest.hexdigest().encode()) produit une chaîne de 88 caractères — deux fois les 44 caractères attendus. Les APIs qui attendent un SHA-256 encodé en Base64 la rejetteront.
Solution : Appelle .digest() (octets bruts) avant l'encodage Base64, pas .hexdigest() (chaîne hex).
import hashlib, base64 hex_str = hashlib.sha256(data).hexdigest() b64 = base64.b64encode(hex_str.encode()) # 88 caractères — incorrect !
import hashlib, base64 raw = hashlib.sha256(data).digest() b64 = base64.b64encode(raw) # 44 caractères — correct
Problème : hashlib.sha256(open('large.iso', 'rb').read()) charge tout le fichier en mémoire. Un fichier de 4 Go nécessite 4 Go de RAM juste pour le calcul du hachage.
Solution : Lis par morceaux avec une boucle et .update(). L'utilisation mémoire reste constante quelle que soit la taille du fichier.
import hashlib
# Charge tout le fichier de 4 Go en mémoire
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() # utilisation mémoire constantehashlib vs hmac vs alternatives — Comparaison rapide
Pour le hachage simple — sommes de contrôle, clés de cache, empreintes de contenu — reste avec hashlib.sha256(). Passe à hmac.new() dès que tu as besoin d'une clé secrète (webhooks, signatures API, authentification par token). Utilise la bibliothèque cryptography uniquement si ton projet l'utilise déjà pour le chiffrement ou TLS — ajouter une dépendance d'extension C juste pour le hachage est disproportionné quand hashlib est déjà basé sur OpenSSL.
Peut-on déchiffrer SHA-256 ? — Hachage vs chiffrement
Réponse courte : non. SHA-256 est une fonction à sens unique. L'algorithme est conçu pour être irréversible — on ne peut pas reconstruire l'entrée originale à partir du condensat de 256 bits. Ce n'est pas une limitation d'implémentation ; c'est une propriété mathématique de la fonction de hachage. L'espace de sortie de 256 bits est astronomiquement grand (2256valeurs possibles), et la fonction élimine de l'information au cours de ses 64 tours de compression.
Des attaquants peuvent tenter des attaques par force brute ou par dictionnaire contre des entrées faibles (mots de passe courants, chaînes courtes), mais pour toute entrée avec une entropie correcte — clés API, tokens aléatoires, contenu de fichiers — inverser SHA-256 est computationnellement infaisable avec le matériel actuel. Si tu as besoin d'une transformation réversible, utilise le chiffrement symétrique :
# Hachage — sens unique, impossible de récupérer l'original import hashlib digest = hashlib.sha256(b"secret-config-value").hexdigest() # Impossible d'obtenir "secret-config-value" à partir du condensat # Chiffrement — bidirectionnel, peut déchiffrer avec la clé 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" — original récupéré
Pour générer rapidement un hachage SHA-256 sans installation, l'outil en ligne fonctionne entièrement dans ton navigateur.
Comment vérifier si une chaîne est un hachage SHA-256 valide en Python
Un condensat SHA-256 hexadécimal valide fait exactement 64 caractères hexadécimaux (0-9, a-f, A-F). Une validation rapide avant de traiter des entrées non fiables évite des erreurs confuses en aval.
import re
def is_sha256_hex(value: str) -> bool:
"""Vérifie si une chaîne correspond au format de condensat SHA-256 hexadécimal."""
return bool(re.fullmatch(r"[a-fA-F0-9]{64}", value))
# Cas de test
print(is_sha256_hex("e3b0c44298fc1c149afbf4c8996fb924"
"27ae41e4649b934ca495991b7852b855")) # True — SHA-256 de la chaîne vide
print(is_sha256_hex("e3b0c44298fc1c14")) # False — trop court
print(is_sha256_hex("zzzz" * 16)) # False — caractères hex invalidesQuestions fréquentes
Comment hacher une chaîne avec SHA-256 en Python ?
Appelle hashlib.sha256() avec la chaîne encodée en bytes. Les chaînes Python sont Unicode, et les fonctions de hachage opèrent sur des octets bruts, donc tu dois appeler .encode("utf-8") en premier. La méthode .hexdigest() renvoie la chaîne hexadécimale classique de 64 caractères.
import hashlib
api_key = "sk_live_9f3a7b2e1d4c"
digest = hashlib.sha256(api_key.encode("utf-8")).hexdigest()
print(digest)
# e3b7c4a1f8d2...64 caractères hexadécimauxPeut-on déchiffrer un hachage SHA-256 pour retrouver le texte original ?
Non. SHA-256 est une fonction à sens unique — elle transforme une entrée de longueur arbitraire en une sortie fixe de 256 bits et élimine la structure en cours de route. Il n'existe pas d'inverse mathématique. Des attaquants peuvent tenter des attaques par force brute ou par tables arc-en-ciel sur des entrées faibles (mots de passe courts, mots courants), mais pour toute entrée avec une entropie raisonnable, inverser SHA-256 est computationnellement infaisable. Si tu as besoin d'une transformation réversible, utilise le chiffrement (AES-GCM, Fernet) plutôt que le hachage.
Quelle est la différence entre .digest() et .hexdigest() ?
.digest() renvoie les 32 octets bruts du hachage sous forme d'objet bytes. .hexdigest() renvoie les mêmes données encodées en chaîne hexadécimale minuscule de 64 caractères. Utilise .digest() quand tu as besoin d'une sortie binaire — pour alimenter HMAC, encoder en Base64, ou écrire dans des protocoles binaires. Utilise .hexdigest() quand tu as besoin d'une chaîne lisible pour les journaux, le stockage en base de données, ou la comparaison de sommes de contrôle.
import hashlib h = hashlib.sha256(b"deployment-v4.2.1") print(len(h.digest())) # 32 (octets) print(len(h.hexdigest())) # 64 (caractères hexadécimaux)
Comment calculer la somme de contrôle SHA-256 d'un fichier en Python ?
Ouvre le fichier en mode binaire et alimente le hasher par morceaux avec .update(). Sur Python 3.11+, utilise hashlib.file_digest() pour une API encore plus simple. N'appelle jamais f.read() sur de gros fichiers — cela charge tout le contenu en mémoire.
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"))Comment créer une signature HMAC-SHA256 en Python ?
Utilise le module hmac avec hashlib.sha256 comme digestmod. Passe la clé secrète et le message en bytes. Le résultat est un hachage avec clé qui prouve à la fois l'intégrité et l'authenticité — le destinataire a besoin de la même clé pour vérifier.
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) # HMAC hex de 64 caractèresComment vérifier si une chaîne est un condensat SHA-256 hexadécimal valide ?
Un condensat SHA-256 en hexadécimal fait exactement 64 caractères hexadécimaux. Utilise une expression régulière ou une simple vérification de longueur et de caractères. L'approche par regex est la plus lisible.
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")) # FalseOutils associés
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.