SHA-256 en Python — Guide hashlib + Exemples de code

·DevOps Engineer & Python Automation Specialist·Révisé parMaria Santos·Publié

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.

Before · text
After · text
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.

Python 3.9+ — hachage SHA-256 minimal
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.

Python 3.9+ — hacher une chaîne
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)
# 7d3f8c2a1b9e4f5d6c8a7b3e2f1d9c4a5b8e7f6d3c2a1b9e4f5d6c8a7b3e2f1d

La 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.

Python 3.9+ — hachage incrémental avec 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())
# Équivalent à hashlib.sha256(b"request_id=req_7f3a91bc&timestamp=1741614120&amount=4999").hexdigest()
Note :.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.

Python 3.9+ — HMAC-SHA256 basique
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ères

La 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.

Python 3.9+ — vérifier une signature webhook
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.

Python 3.9+ — signer une requête API avec HMAC-SHA256
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.

Python 3.9+ — HMAC-SHA256 encodé en Base64
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).

Python 3.9+ — hacher un datetime et un UUID
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 :

Python 3.9+ — hacher un objet personnalisé
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 machines
Note :Trie toujours les clés du dict (sort_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.

Python 3.9+ — somme de contrôle SHA-256 d'un fichier (par morceaux)
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.

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())

Vérifier un fichier téléchargé contre une somme de contrôle connue

Python 3.9+ — vérification de somme de contrôle
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é")
Note :Utilise toujours 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.

Python 3.9+ — SHA-256 encodé en Base64
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
Avertissement :Encoder en Base64 la chaîne hexadécimale au lieu des octets bruts est une erreur courante qui produit une sortie deux fois plus longue qu'attendu. Les APIs la rejetteront, et le message d'erreur ne donne généralement aucun indice sur la cause. Appelle toujours .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ètre / Méthode
Type
Description
data (positionnel)
bytes
Données initiales à hacher — équivalent à appeler update(data) immédiatement après la construction
.update(data)
bytes
Alimente des octets supplémentaires dans l'état de hachage — peut être appelé plusieurs fois pour une entrée fragmentée
.digest()
→ bytes
Renvoie le condensat binaire brut de 32 octets — à utiliser pour les entrées HMAC, les protocoles binaires, l'encodage Base64
.hexdigest()
→ str
Renvoie la chaîne hexadécimale en minuscules de 64 caractères — la représentation standard pour les sommes de contrôle et la vérification
.copy()
→ objet hash
Renvoie un clone de l'état de hachage actuel — permet de bifurquer un condensat sans tout recalculer depuis le début
hashlib.sha256()
constructeur
Crée un nouvel objet de hachage SHA-256 basé sur OpenSSL sous CPython — usedfips=True sur 3.9+ restreint aux algorithmes approuvés FIPS

Paramètres de hmac.new() pour le hachage avec clé :

Paramètre
Type
Description
key
bytes
La clé secrète — doit être de type bytes, pas str
msg
bytes | None
Message initial à authentifier — None par défaut, update() peut être appelé ensuite
digestmod
str | callable
Algorithme de hachage : passer hashlib.sha256 ou la chaîne "sha256"

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.

Python 3.9+ — SHA-256 avec la bibliothèque 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 octets bruts

print(result.hex())  # chaîne hex de 64 caractères
# a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db
Avertissement :La bibliothèque 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

Python 3.9+ — hacher une sauvegarde de config avec gestion des erreurs
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

Python 3.9+ — hacher une réponse API
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.

bash — hacher une chaîne depuis la ligne de commande
# 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
bash — hacher un fichier
# 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
Note :Utilise toujours 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 :

bash — installer pycryptodome
pip install pycryptodome
Python 3.9+ — SHA-256 avec 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 :

Python 3.9+ — hachage de fichiers en lot avec hashlib
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.

bash — installer rich
pip install rich
Python 3.9+ — sortie rich pour la vérification de hachages
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,
)
Note :La sortie rich est uniquement pour l'affichage terminal. N'écris pas de codes d'échappement ANSI dans des fichiers journaux ou des réponses API — supprime-les avec 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.

Python 3.9+ — hacher de gros fichiers avec progression
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

Python 3.9+ — hacher des enregistrements individuels dans un flux NDJSON
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")
Note :Passe du simple 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

Passer un str à la place de bytes à hashlib.sha256()

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.

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()
# Fonctionne — renvoie une chaîne hex de 64 caractères
Utiliser == à la place de hmac.compare_digest() pour la vérification de signature

Problè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.

Before · Python
After · Python
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)
Encoder en Base64 la chaîne hex au lieu des octets bruts

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).

Before · Python
After · Python
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
Charger un gros fichier entièrement en mémoire avant le hachage

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.

Before · Python
After · Python
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 constante

hashlib vs hmac vs alternatives — Comparaison rapide

Méthode
Sortie
Clé secrète
Vitesse
Fichiers en flux
Installation requise
Types personnalisés
hashlib.sha256()
hex / bytes
Rapide (C/OpenSSL)
✓ via update()
Non (stdlib)
encode() manuel
hmac.new()
hex / bytes
Rapide (C/OpenSSL)
✓ via update()
Non (stdlib)
encode() manuel
hashlib.file_digest()
hex / bytes
Rapide (zéro copie)
✓ (intégré)
Non (3.11+)
encode() manuel
cryptography hashes.SHA256()
bytes
Rapide (OpenSSL)
✓ via update()
pip install
encode() manuel
subprocess openssl dgst
chaîne hex
✗ / ✓
Plus lent (fork)
✓ (niveau OS)
openssl système
encode() manuel
pyhashcat / custom
variable
Accéléré GPU
pip install
encode() manuel

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 :

Python 3.9+ — chiffrement vs hachage
# 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.

Python 3.9+ — valider le format SHA-256
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 invalides
Note :Cela valide uniquement le format, pas si le hachage a été calculé à partir d'une entrée particulière. Il est impossible de savoir si une chaîne hexadécimale de 64 caractères est un "vrai" condensat SHA-256 ou simplement du hex aléatoire — la sortie de SHA-256 est indiscernable de données aléatoires par conception.

Questions 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.

Python
import hashlib

api_key = "sk_live_9f3a7b2e1d4c"
digest = hashlib.sha256(api_key.encode("utf-8")).hexdigest()
print(digest)
# e3b7c4a1f8d2...64 caractères hexadécimaux

Peut-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.

Python
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.

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"))

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.

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)  # HMAC hex de 64 caractères

Comment 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.

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

Outils associés

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 SantosRéviseur technique

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.