SHA-256 em Python — hashlib e exemplos de código
Use o Gerador de Hash SHA-256 gratuito diretamente no seu navegador — sem instalação.
Experimentar Gerador de Hash SHA-256 online →Todo pipeline de deploy que já construí precisou, em algum momento, verificar o checksum de um arquivo, assinar um payload de webhook ou criar uma impressão digital de chave de cache. O hashing SHA-256 em Python com o módulo embutido hashlib resolve todos esses casos — e você já o tem instalado. hashlib.sha256() encapsula a implementação do OpenSSL no CPython, portanto é rápido e compatível com FIPS por padrão. Para um hash rápido sem escrever código, o gerador SHA-256 online entrega o resultado instantaneamente. Todos os exemplos são para Python 3.9+.
- ✓hashlib.sha256(data).hexdigest() é a forma padrão de calcular o hash de bytes — parte da stdlib, apoiado pelo OpenSSL.
- ✓Strings devem ser codificadas em bytes primeiro: hashlib.sha256("texto".encode("utf-8")).
- ✓Para checksums de arquivos, alimente partes via .update() — nunca carregue um arquivo grande inteiro na memória.
- ✓HMAC-SHA256 requer o módulo hmac: hmac.new(key, msg, hashlib.sha256) — o SHA-256 sozinho não possui chave.
O que é o hash SHA-256?
SHA-256 (Secure Hash Algorithm, 256 bits) recebe uma entrada de comprimento arbitrário e produz um digest fixo de 256 bits (32 bytes). A mesma entrada sempre gera a mesma saída, mas mesmo uma única alteração de bit na entrada produz um hash completamente diferente — essa propriedade é chamada de efeito avalanche. SHA-256 faz parte da família SHA-2, padronizada pelo NIST, e é a base de impressões digitais de certificados TLS, IDs de commits do Git, cabeçalhos de blocos do Bitcoin e verificação de integridade de arquivos. O algoritmo usa uma construção de Merkle-Damgård com 64 rodadas de compressão para produzir sua saída de 256 bits.
deployment-v4.2.1
a1f7c3d8e9b2...27ae41e4649b (64 caracteres hex)
O digest hexadecimal acima é a representação padrão — 64 caracteres hexadecimais, sempre com o mesmo comprimento independentemente de você calcular o hash de um único byte ou de uma imagem de disco completa.
hashlib.sha256() — A abordagem com a biblioteca padrão
O módulo hashlib acompanha toda instalação Python — não é necessário pip install. Chame hashlib.sha256() com um argumento do tipo bytes para criar um objeto de hash, depois recupere o resultado com .hexdigest() (string hexadecimal) ou .digest() (bytes brutos). O nome da função é em minúsculas: sha256, não SHA256.
import hashlib # Calcular hash de uma string de bytes diretamente digest = hashlib.sha256(b"deployment-v4.2.1").hexdigest() print(digest) # a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db
O erro mais comum com hashlib.sha256() é passar uma str em vez de bytes. Strings Python são Unicode e funções de hash operam sobre bytes brutos. Você deve chamar .encode("utf-8") antes de calcular o hash. Isso pega quase todo mundo na primeira vez.
import hashlib
# Strings devem ser codificadas em bytes antes do hash
config_key = "redis://cache.internal:6379/0"
digest = hashlib.sha256(config_key.encode("utf-8")).hexdigest()
print(digest)
# 7d3f8c2a1b9e4f5d6c8a7b3e2f1d9c4a5b8e7f6d3c2a1b9e4f5d6c8a7b3e2f1dO método .update() permite alimentar dados de forma incremental. Chamar h.update(a); h.update(b) é equivalente a hashlib.sha256(a + b). É assim que você calcula o hash de arquivos em partes sem carregar o conteúdo inteiro na memória.
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()) # Equivalente a hashlib.sha256(b"request_id=req_7f3a91bc×tamp=1741614120&amount=4999").hexdigest()
.digest() retorna 32 bytes brutos. .hexdigest() retorna uma string hexadecimal de 64 caracteres. Use .digest() ao alimentar o resultado em HMAC, codificação Base64 ou protocolos binários. Use .hexdigest() para logs, colunas de banco de dados e comparação de checksums.HMAC-SHA256 — Hash com chave usando o módulo hmac
SHA-256 sozinho não tem o conceito de chave secreta — qualquer pessoa com a mesma entrada pode calcular o mesmo hash. Se você precisa provar que uma mensagem veio de um remetente específico (verificação de webhook, assinatura de requisição de API, autenticação de token), você precisa do HMAC. O módulo hmac faz parte da biblioteca padrão do Python e incorpora a chave no processo de hashing, de modo que somente quem possui a chave pode produzir ou verificar o mesmo digest.
import hmac
import hashlib
# Verificação de assinatura de 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)
# digest HMAC-SHA256 hexadecimal de 64 caracteresPara verificar um HMAC recebido, use hmac.compare_digest() em vez do operador ==. O operador de igualdade é vulnerável a ataques de temporização — ele interrompe a comparação no primeiro byte diferente, e um atacante pode medir os tempos de resposta para adivinhar a assinatura correta byte a byte. compare_digest() executa em tempo constante independentemente de onde ocorre a divergência.
import hmac
import hashlib
def verify_webhook(payload: bytes, received_sig: str, secret: bytes) -> bool:
"""Verificar assinatura de webhook com comparação em tempo constante."""
expected = hmac.new(secret, payload, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, received_sig)
# Simulando verificação de webhook no estilo Stripe
incoming_payload = b'{"event":"payment.completed","amount":4999}'
incoming_signature = "a1b2c3d4e5f6..." # do cabeçalho X-Signature
webhook_secret = b"whsec_9f3a7b2e1d4c"
if verify_webhook(incoming_payload, incoming_signature, webhook_secret):
print("Assinatura válida — processar o evento")
else:
print("Assinatura inválida — rejeitar a requisição")Assinatura de requisição com HMAC-SHA256
A assinatura de requisições de API segue o mesmo princípio: construa uma string canônica a partir dos componentes da requisição (método, caminho, timestamp, hash do corpo) e assine-a com sua chave secreta. AWS Signature V4, Stripe e webhooks do GitHub usam variações desse padrão.
import hmac
import hashlib
import time
def sign_request(method: str, path: str, body: bytes, secret: bytes) -> str:
"""Criar assinatura HMAC-SHA256 para uma requisição de API."""
timestamp = str(int(time.time()))
body_hash = hashlib.sha256(body).hexdigest()
# String canônica: método + caminho + timestamp + hash do corpo
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}"
# Uso
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 codificado em Base64
Algumas APIs (AWS Signature V4, gateways de pagamento) esperam o resultado do HMAC como uma string codificada em Base64 em vez de hexadecimal. A diferença: hex usa 64 caracteres, Base64 usa 44 caracteres para o mesmo digest de 32 bytes.
import hmac
import hashlib
import base64
secret = b"webhook_secret_9f3a"
message = b"POST /api/v2/events 1741614120"
# Saída hex: 64 caracteres
hex_sig = hmac.new(secret, message, hashlib.sha256).hexdigest()
print(f"Hex: {hex_sig}")
# Saída Base64: 44 caracteres (mais curta, comum em cabeçalhos HTTP)
raw_sig = hmac.new(secret, message, hashlib.sha256).digest()
b64_sig = base64.b64encode(raw_sig).decode("ascii")
print(f"Base64: {b64_sig}")Hash de datetime, UUID e objetos customizados
SHA-256 opera sobre bytes brutos, portanto tipos não-bytes — datetime, UUID, dataclasses, modelos Pydantic — devem ser serializados em bytes antes do hash. Não há conversão automática; você escolhe a representação canônica. Para hashing determinístico entre sistemas, sempre use uma codificação explícita e um formato de serialização estável (ISO 8601 para datetimes, a forma de string padrão para UUIDs, JSON com chaves ordenadas para dicts).
import hashlib
import uuid
from datetime import datetime, timezone
# datetime — use ISO 8601 com offset UTC explícito para portabilidade
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"hash do datetime: {time_hash[:16]}...")
# UUID — calcular hash da forma de string canônica (minúsculas, com hífens)
record_id = uuid.uuid4()
uuid_hash = hashlib.sha256(str(record_id).encode("utf-8")).hexdigest()
print(f"hash do UUID: {uuid_hash[:16]}...")Para objetos customizados, serialize para uma representação bytes canônica antes do hash. JSON com chaves ordenadas funciona bem para objetos semelhantes a dicts:
import hashlib
import json
from dataclasses import dataclass, asdict
@dataclass
class Evento:
id: str
tipo: str
valor: int
timestamp: str
def hash_evento(evento: Evento) -> str:
"""Calcular hash de uma instância de dataclass usando JSON com chaves ordenadas para determinismo."""
canonical = json.dumps(asdict(evento), sort_keys=True, separators=(",", ":"))
return hashlib.sha256(canonical.encode("utf-8")).hexdigest()
e = Evento(id="evt_4f2a", tipo="pagamento.concluido", valor=4999, timestamp="2026-03-28T12:00:00Z")
print(hash_evento(e)) # estável entre execuções e máquinassort_keys=True) ao calcular o hash de objetos serializados em JSON. A ordem de inserção de dicts é preservada no Python 3.7+, mas pode diferir entre caminhos de serialização, produzindo hashes diferentes para dados idênticos.Checksum SHA-256 de arquivo — verificar downloads e artefatos
Calcular o checksum SHA-256 de um arquivo é um dos usos mais comuns do algoritmo. Você o encontra em todo lugar: páginas de release de binários Go, arquivos wheel Python, manifestos de imagem Docker, atualizações de firmware. A chave é ler o arquivo em partes em vez de carregá-lo todo de uma vez — uma imagem ISO de 2 GB não deve exigir 2 GB de RAM só para calculá-la.
import hashlib
def sha256_checksum(filepath: str, chunk_size: int = 8192) -> str:
"""Calcular hash SHA-256 de um arquivo, lendo em partes para economizar memória."""
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()
# Hash de um artefato de release
checksum = sha256_checksum("/tmp/release-v4.2.1.tar.gz")
print(f"SHA-256: {checksum}")O Python 3.11 adicionou hashlib.file_digest(), que faz a leitura em partes internamente e pode usar otimizações de cópia zero em plataformas compatíveis. Se você está no 3.11 ou posterior, prefira-o ao loop manual.
import hashlib
with open("/tmp/release-v4.2.1.tar.gz", "rb") as f:
digest = hashlib.file_digest(f, "sha256")
print(digest.hexdigest())Verificar um arquivo baixado contra um checksum conhecido
import hashlib
import hmac as hmac_mod # apenas para compare_digest
def verify_checksum(filepath: str, expected_hex: str) -> bool:
"""Verificar checksum SHA-256 com comparação em tempo constante."""
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())
# Verificar um artefato de release
expected = "a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db"
if verify_checksum("/tmp/release-v4.2.1.tar.gz", expected):
print("Checksum correto — arquivo íntegro")
else:
print("Checksum inválido — arquivo pode estar corrompido ou adulterado")hmac.compare_digest() para comparação de checksums, mesmo quando não há chave secreta envolvida. A comparação em tempo constante evita vazamentos de informação baseados em temporização. O operador == funciona corretamente, mas não é seguro para contextos sensíveis à segurança.SHA-256 com codificação Base64
Alguns protocolos esperam o digest SHA-256 como string Base64 em vez de hexadecimal. Cabeçalhos HTTP como Content-Digest e Integrity (Subresource Integrity em navegadores) usam Base64, e assinaturas JWT são codificadas em Base64url. O ponto chave é codificar em Base64 os bytes brutos do .digest(), não a string hexadecimal.
import hashlib
import base64
data = b"integrity check payload"
# Correto: Base64 de bytes brutos (32 bytes → 44 caracteres Base64)
raw_digest = hashlib.sha256(data).digest()
b64_digest = base64.b64encode(raw_digest).decode("ascii")
print(f"sha256-{b64_digest}")
# sha256-<44 caracteres>
# Errado: Base64 da string hexadecimal (64 bytes ASCII → 88 caracteres Base64 — o dobro do tamanho)
hex_digest = hashlib.sha256(data).hexdigest()
wrong = base64.b64encode(hex_digest.encode()).decode()
print(f"Comprimento errado: {len(wrong)} chars") # 88 — não é o que as APIs esperam.digest(), não .hexdigest(), antes da codificação Base64.Referência do hashlib.sha256()
O construtor e os métodos de um objeto de hash SHA-256:
Parâmetros de hmac.new() para hash com chave:
A biblioteca cryptography — Uma API alternativa para SHA-256
O pacote cryptography oferece uma API diferente para SHA-256 por meio de suas primitivas hazmat. Raramente a uso quando tudo que preciso é um hash — o hashlib é mais simples e não tem dependência externa. Mas se seu projeto já depende do cryptography para TLS, X.509 ou criptografia simétrica, usar sua API de hash mantém tudo sob uma única biblioteca e oferece tratamento de erros consistente.
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 bytes brutos print(result.hex()) # string hexadecimal de 64 caracteres # a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db
cryptography requer pip install cryptography. O objeto de hash é de uso único: chamar .finalize() uma segunda vez lança AlreadyFinalized. Use .copy() antes de finalizar se precisar ramificar o estado do hash.Hash de arquivo e de resposta de API
Dois cenários surgem constantemente: calcular o hash de um arquivo em disco para verificar um artefato de release, e calcular o hash do corpo de uma resposta HTTP para usar como chave de cache ou verificar um webhook.
Ler arquivo → Calcular SHA-256 → Comparar
import hashlib
import sys
def hash_file_safe(filepath: str) -> str | None:
"""Calcular hash de um arquivo com tratamento adequado de erros."""
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"Erro: {filepath} não encontrado", file=sys.stderr)
return None
except PermissionError:
print(f"Erro: sem permissão de leitura para {filepath}", file=sys.stderr)
return None
result = hash_file_safe("/etc/nginx/nginx.conf")
if result:
print(f"SHA-256: {result}")Resposta HTTP → Hash do corpo como chave de cache
import hashlib
import urllib.request
import json
def fetch_and_hash(url: str) -> tuple[dict, str]:
"""Buscar JSON de uma API e retornar tanto os dados quanto seu hash 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"Falha ao buscar {url}: {exc}") from exc
# Chave de cache baseada no conteúdo da resposta
data, digest = fetch_and_hash("https://api.exchange.internal/v2/rates")
print(f"Hash da resposta: {digest[:16]}...")
print(f"EUR/BRL: {data.get('rates', {}).get('EUR', 'N/A')}")Para uma verificação rápida sem código, o gerador SHA-256 do ToolDeck roda inteiramente no seu navegador.
Hash SHA-256 na linha de comando
Às vezes você precisa de um hash rápido no terminal durante um incidente ou deploy. O módulo hashlib do Python não tem subcomando de CLI embutido (ao contrário do python3 -m json.tool), mas você pode usar um one-liner ou ferramentas do sistema.
# One-liner 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 (multiplataforma) echo -n "deployment-v4.2.1" | openssl dgst -sha256
# Hash de um tarball de release sha256sum release-v4.2.1.tar.gz # ou openssl dgst -sha256 release-v4.2.1.tar.gz # Verificar contra um checksum conhecido echo "a8f5f167f44f4964e6c998dee827110c release-v4.2.1.tar.gz" | sha256sum -c - # release-v4.2.1.tar.gz: OK
echo -n (sem nova linha no final) ao calcular hash de strings na linha de comando. Um echo simples acrescenta \n, o que altera o hash. Esta é a principal razão pela qual as pessoas obtêm hashes diferentes entre Python e o shell.Alternativa de alta performance — hashlib com OpenSSL e pycryptodome
No CPython, hashlib.sha256() já delega para a implementação C do OpenSSL, portanto é rápido — tipicamente 500+ MB/s em hardware moderno.
Se o hashing SHA-256 aparecer no seu profiler — por exemplo, ao calcular checksums de milhares de arquivos num pipeline de CI ou ao calcular o hash de cada corpo de requisição num gateway de API de alta demanda — existem duas opções: otimizar o padrão de chamada do hashlib, ou mudar para pycryptodome para uma API de criptografia unificada que também cobre SHA-3 e BLAKE2:
pip install pycryptodome
from Crypto.Hash import SHA256 h = SHA256.new() h.update(b"deployment-v4.2.1") print(h.hexdigest()) # a8f5f167f44f4964e6c998dee827110c3f1de4d0280c68cba98cf70b4b5157db
Para hashing paralelo de arquivos em alta demanda, os maiores ganhos vêm da redução do overhead do Python por meio de partes maiores e threads:
import hashlib
import os
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
def hash_file(path: Path) -> tuple[str, str]:
"""Calcular hash de um único arquivo e retornar (caminho, digest hex)."""
h = hashlib.sha256()
with open(path, "rb") as f:
for chunk in iter(lambda: f.read(65536), b""): # partes de 64 KB
h.update(chunk)
return str(path), h.hexdigest()
def hash_directory(directory: str, pattern: str = "*.tar.gz") -> dict[str, str]:
"""Calcular hash de todos os arquivos correspondentes em paralelo usando 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
# Calcular hash de todos os artefatos de release em paralelo
checksums = hash_directory("/var/releases", "*.tar.gz")
for path, digest in checksums.items():
print(f"{digest} {path}")Usar partes de 64 KB em vez de 8 KB reduz em 8x o número de chamadas Python para C. Threads funcionam bem aqui porque o GIL é liberado durante o hashing em nível C — o gargalo é a E/S de disco, não a CPU.
Saída no terminal com destaque de sintaxe
A biblioteca rich é útil quando você precisa verificar um lote de arquivos e quer uma tabela mostrando o status aprovado/reprovado por arquivo em vez de saída hexadecimal rolando pela tela.
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:
"""Calcular hash dos arquivos e exibir resultados com verificação colorida."""
table = Table(title="Verificação SHA-256")
table.add_column("Arquivo", style="cyan")
table.add_column("SHA-256", style="dim", max_width=20)
table.add_column("Status")
for filepath in files:
h = hashlib.sha256()
with open(filepath, "rb") as f:
for chunk in iter(lambda: f.read(8192), b""):
h.update(chunk)
digest = h.hexdigest()
name = Path(filepath).name
status = "[green]✓ OK[/green]" if expected.get(name) == digest else "[red]✗ DIVERGÊNCIA[/red]"
table.add_row(name, f"{digest[:16]}...", status)
console.print(table)
# Uso
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 redirecione para um arquivo com Console(file=open(...)).Trabalhando com arquivos grandes
O padrão de .update() em partes lida com arquivos de qualquer tamanho com uso constante de memória. Para arquivos muito grandes (imagens de disco de vários GB, backups de banco de dados), a preocupação principal muda de memória para feedback ao usuário — calcular o hash de 10 GB a 500 MB/s ainda leva 20 segundos, e o silêncio durante esse tempo deixa as pessoas preocupadas.
import hashlib
import os
def sha256_with_progress(filepath: str) -> str:
"""Calcular hash de um arquivo grande com relatório de progresso na 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): # partes de 1 MB
h.update(chunk)
bytes_read += len(chunk)
pct = (bytes_read / file_size) * 100
print(f"\r Calculando hash: {pct:.1f}% ({bytes_read >> 20} MB / {file_size >> 20} MB)",
end="", flush=True)
print() # nova linha após o progresso
return h.hexdigest()
digest = sha256_with_progress("/mnt/backups/db-snapshot-2026-03.sql.gz")
print(f"SHA-256: {digest}")NDJSON / JSON Lines — Hash de cada registro separadamente
import hashlib
import json
def hash_ndjson_records(filepath: str) -> dict[str, str]:
"""Calcular hash de cada registro JSON em um arquivo NDJSON para deduplicação."""
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)
# Normalizar antes do hash: ordenar chaves para saída determinística
canonical = json.dumps(record, sort_keys=True, separators=(",", ":"))
digest = hashlib.sha256(canonical.encode("utf-8")).hexdigest()
if digest in seen:
print(f"Linha {line_num}: duplicata da linha {seen[digest]}")
else:
seen[digest] = line_num
except json.JSONDecodeError:
print(f"Linha {line_num}: JSON inválido, ignorado")
print(f"Processadas {line_num} linhas, {len(seen)} registros únicos")
return seen
hash_ndjson_records("telemetry-events-2026-03.ndjson")hashlib.sha256(data) para o loop de.update() em partes quando os arquivos ultrapassarem 50–100 MB. Abaixo desse limite, ler o arquivo inteiro com f.read() é suficiente — o uso de memória será aproximadamente igual ao tamanho do arquivo.Erros comuns
Problema: hashlib.sha256('texto') lança TypeError: Unicode-objects must be encoded before hashing. A função requer bytes, não str.
Solução: Codifique a string primeiro: hashlib.sha256('texto'.encode('utf-8')). Ou use um literal b'' para valores fixos no código.
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()
# Correto — retorna string hexadecimal de 64 caracteresProblema: O operador == interrompe a comparação no primeiro byte diferente. Um atacante pode medir o tempo de resposta para adivinhar a assinatura correta byte a byte.
Solução: Use hmac.compare_digest() para todas as comparações sensíveis à segurança — ele executa em tempo constante independentemente de onde ocorre a divergência.
received_sig = request.headers["X-Signature"]
expected_sig = hmac.new(key, body, hashlib.sha256).hexdigest()
if received_sig == expected_sig: # vulnerável a ataque de temporização
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): # tempo constante
process_webhook(body)Problema: base64.b64encode(digest.hexdigest().encode()) produz uma string de 88 caracteres — o dobro dos 44 esperados. APIs que esperam SHA-256 codificado em Base64 vão rejeitá-la.
Solução: Chame .digest() (bytes brutos) antes da codificação Base64, não .hexdigest() (string hexadecimal).
import hashlib, base64 hex_str = hashlib.sha256(data).hexdigest() b64 = base64.b64encode(hex_str.encode()) # 88 chars — errado!
import hashlib, base64 raw = hashlib.sha256(data).digest() b64 = base64.b64encode(raw) # 44 chars — correto
Problema: hashlib.sha256(open('large.iso', 'rb').read()) carrega o arquivo inteiro na memória. Um arquivo de 4 GB requer 4 GB de RAM só para a computação do hash.
Solução: Leia em partes com um loop e .update(). O uso de memória permanece constante independentemente do tamanho do arquivo.
import hashlib
# Carrega 4 GB inteiros na memória
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() # uso de memória constantehashlib vs hmac vs alternativas — Comparação rápida
Para hashing direto — checksums, chaves de cache, fingerprinting de conteúdo — use hashlib.sha256(). Mude para hmac.new() assim que precisar de uma chave secreta (webhooks, assinaturas de API, autenticação de token). Recorra à biblioteca cryptography somente se seu projeto já a utiliza para criptografia ou TLS — adicionar uma dependência de extensão C apenas para hashing é excessivo quando o hashlib já usa o OpenSSL por baixo.
É possível descriptografar SHA-256? — Hashing vs criptografia
Resposta curta: não. SHA-256 é uma função unidirecional. O algoritmo é projetado para ser irreversível — você não pode reconstruir a entrada original a partir do digest de 256 bits. Esta não é uma limitação de implementação; é uma propriedade matemática da função de hash. O espaço de saída de 256 bits é astronomicamente grande (2256 valores possíveis), e a função descarta informação durante suas 64 rodadas de compressão.
Atacantes podem tentar força bruta ou ataques de dicionário contra entradas fracas (senhas comuns, strings curtas), mas para qualquer entrada com entropia razoável — chaves de API, tokens aleatórios, conteúdo de arquivo — reverter o SHA-256 é computacionalmente inviável com o hardware atual. Se você precisar de transformação reversível, use criptografia simétrica:
# Hashing — unidirecional, não é possível recuperar o original import hashlib digest = hashlib.sha256(b"secret-config-value").hexdigest() # Não há como obter "secret-config-value" de volta a partir do digest # Criptografia — bidirecional, pode descriptografar com a chave 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 recuperado
Para gerar um hash SHA-256 rapidamente sem instalar nada, a ferramenta online roda inteiramente no seu navegador.
Como verificar se uma string é um hash SHA-256 válido em Python
Um digest SHA-256 hexadecimal válido tem exatamente 64 caracteres hexadecimais (0-9, a-f, A-F). Uma validação rápida antes de processar entradas não confiáveis evita erros confusos mais adiante.
import re
def is_sha256_hex(value: str) -> bool:
"""Verificar se uma string corresponde ao formato de digest SHA-256 hexadecimal."""
return bool(re.fullmatch(r"[a-fA-F0-9]{64}", value))
# Casos de teste
print(is_sha256_hex("e3b0c44298fc1c149afbf4c8996fb924"
"27ae41e4649b934ca495991b7852b855")) # True — SHA-256 da string vazia
print(is_sha256_hex("e3b0c44298fc1c14")) # False — muito curto
print(is_sha256_hex("zzzz" * 16)) # False — caracteres hex inválidosPerguntas frequentes
Como calcular o hash de uma string com SHA-256 em Python?
Chame hashlib.sha256() com a string codificada em bytes. Strings em Python são Unicode e funções de hash operam sobre bytes brutos, portanto você deve chamar .encode("utf-8") primeiro. O método .hexdigest() retorna a conhecida string hexadecimal de 64 caracteres.
import hashlib
api_key = "sk_live_9f3a7b2e1d4c"
digest = hashlib.sha256(api_key.encode("utf-8")).hexdigest()
print(digest)
# e3b7c4a1f8d2...64 caracteres hexadecimaisÉ possível descriptografar um hash SHA-256 e recuperar o texto original?
Não. SHA-256 é uma função unidirecional — ela mapeia uma entrada de comprimento arbitrário para uma saída fixa de 256 bits e descarta a estrutura durante o processo. Não existe inversa matemática. Atacantes podem tentar força bruta ou tabelas rainbow contra entradas fracas (senhas curtas, palavras comuns), mas para qualquer entrada com entropia razoável, reverter o SHA-256 é computacionalmente inviável. Se você precisar de transformação reversível, use criptografia (AES-GCM, Fernet) em vez de hash.
Qual a diferença entre .digest() e .hexdigest()?
.digest() retorna os 32 bytes brutos do hash como um objeto bytes. .hexdigest() retorna os mesmos dados codificados como uma string hexadecimal de 64 caracteres em minúsculas. Use .digest() quando precisar de saída binária — para alimentar HMAC, codificação Base64 ou protocolos binários. Use .hexdigest() quando precisar de uma string legível para logs, armazenamento em banco de dados ou comparação de checksums.
import hashlib h = hashlib.sha256(b"deployment-v4.2.1") print(len(h.digest())) # 32 (bytes) print(len(h.hexdigest())) # 64 (caracteres hexadecimais)
Como calcular o checksum SHA-256 de um arquivo em Python?
Abra o arquivo em modo binário e alimente-o ao hasher em partes com .update(). No Python 3.11+, use hashlib.file_digest() para uma API ainda mais simples. Nunca chame f.read() em arquivos grandes — isso carrega o arquivo inteiro na memória.
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"))Como criar uma assinatura HMAC-SHA256 em Python?
Use o módulo hmac com hashlib.sha256 como digestmod. Passe a chave secreta e a mensagem como bytes. O resultado é um hash com chave que prova tanto a integridade quanto a autenticidade — o receptor precisa da mesma chave para verificar.
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 hexadecimal de 64 caracteresComo verificar se uma string é um digest SHA-256 hexadecimal válido?
Um digest SHA-256 hexadecimal tem exatamente 64 caracteres hexadecimais. Use uma expressão regular ou uma verificação simples de comprimento mais caracteres. A abordagem com regex é a mais legível.
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")) # FalseFerramentas relacionadas
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.