Trilha 13 · Segurança e criptografia

Assinaturas e certificados

A lição anterior deixou um buraco: Diffie-Hellman protege contra quem escuta, mas não contra quem se coloca no meio. Cifrar sem saber com quem se fala é trancar a porta sem olhar quem está dentro. Esta lição fecha esse buraco com duas ideias — assinar e atestar — e explica por que aquele cadeado no navegador promete menos do que a maioria das pessoas imagina.

① Intuição

Um selo que qualquer um confere e ninguém falsifica

Um selo de cera real cumpria duas funções ao mesmo tempo: só o rei tinha o anel que o produzia, e qualquer súdito reconhecia o desenho. Além disso, se alguém abrisse a carta, o selo quebrava. A assinatura digital faz as três coisas — autoria, verificação pública e detecção de adulteração — com uma vantagem decisiva: ela depende do conteúdo. Mudar uma vírgula invalida a assinatura.

Mas o selo só funciona porque o súdito já sabe qual é o desenho do anel do rei. Na internet você não conhece a chave pública de nenhum site de antemão. É por isso que a assinatura sozinha não basta: um impostor também assina, só que com a chave dele. Falta responder de quem é esta chave — e a resposta é uma cadeia de atestados que termina em alguém que você já confiava antes de a conexão existir.

Confiança não se cria do nada; ela se delega. Seu sistema operacional veio com cerca de 150 certificados-raiz instalados de fábrica. Você nunca escolheu confiar neles — a Microsoft, a Apple, o Google e a Mozilla escolheram por você, e mantêm programas rígidos que auditam e removem autoridades que erram. Toda a segurança do HTTPS repousa sobre esse conjunto: se uma única raiz emitir um certificado indevido, ela pode se passar por qualquer site do mundo.
② Visualização interativa

Assinar, adulterar, e a cadeia quebrando

Na primeira aba, edite a mensagem depois de assinada e veja a verificação falhar imediatamente. Na segunda, percorra a cadeia de certificados e provoque cada tipo de erro que o navegador reporta — autoassinado, expirado, nome errado, CA desconhecida.

Uma assinatura digital é a criptografia de chave pública ao contrário: assina-se com a chave privada e qualquer um verifica com a pública. Isso não esconde nada — prova autoria e integridade.

1. O BANCO ASSINA (com a chave privada)
Transferir R$ 100 para a conta 4471
hash da mensagem → 123
assinatura = hashd mod n = 123103 mod 143 = 85
2. EM TRÂNSITO — edite a mensagem, como faria um atacante
a assinatura (85) segue junto, inalterada — o atacante não consegue recalculá-la sem a chave privada
3. VOCÊ VERIFICA (com a chave pública — que é, aliás, pública)
hash da mensagem recebida = 123
assinaturae mod n = 857 mod 143 = 123
✓ os dois batem — assinatura VÁLIDA
A mensagem chegou como saiu. Repare no que a verificação também prova: só quem tem a chave privada poderia ter produzido esse número. Daí o não-repúdio — o banco não pode depois alegar que não emitiu essa ordem.
Assinatura ou MAC? Um MAC (HMAC) também detecta adulteração, é muito mais rápido e usa uma chave compartilhada — mas, por isso mesmo, qualquer um dos dois lados poderia tê-lo gerado, e ele não serve como prova diante de terceiros. Use HMAC entre partes que já confiam uma na outra; use assinatura quando o mundo inteiro precisa poder verificar.
③ Explicação técnica

Como assinar

# Assinatura digital: a chave pública ao contrário.
#
#   CIFRAR:   chave PÚBLICA fecha  →  chave PRIVADA abre
#   ASSINAR:  chave PRIVADA assina →  chave PÚBLICA verifica
#
# Assinar não esconde nada. Prova AUTORIA e INTEGRIDADE.

# Assina-se o HASH, não o documento — por dois motivos:
#   1. o documento pode ter gigabytes; o hash tem 32 bytes
#   2. operações assimétricas só funcionam em blocos pequenos
assinatura = assinar(chave_privada, sha256(documento))

# Verificar: recalcule o hash e confira contra a assinatura
valida = verificar(chave_publica, sha256(documento), assinatura)

# ⚠ Consequência direta de assinar o hash: a segurança da
# assinatura NÃO PASSA da segurança da função hash. Se alguém
# consegue produzir dois documentos com o mesmo hash, pode obter
# sua assinatura num e colá-la no outro. Foi por isso que colisões
# em MD5 e SHA-1 aposentaram esses algoritmos das assinaturas.

from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
priv = Ed25519PrivateKey.generate()
pub  = priv.public_key()

sig = priv.sign(b"transferir R$ 100")
pub.verify(sig, b"transferir R$ 100")   # exceção se não bater

HMAC ou assinatura?

# MAC ou ASSINATURA? A pergunta é: quem precisa verificar?
#
# HMAC — chave COMPARTILHADA
#   . rápido (só hash), chaves curtas
#   . os dois lados têm a mesma chave
#   . logo, cada lado poderia ter forjado a etiqueta do outro
#   . → não serve como prova perante terceiros
tag = hmac.new(chave_compartilhada, mensagem, hashlib.sha256).digest()

# ASSINATURA — par de chaves
#   . mais lenta, chaves maiores
#   . só o dono da privada pode gerar; o mundo todo verifica
#   . → NÃO-REPÚDIO: o autor não pode negar depois
sig = chave_privada.sign(mensagem)

# Use HMAC entre partes que já confiam uma na outra e já
# compartilham um segredo: webhooks, cookies de sessão, tokens
# internos. Use assinatura quando qualquer um precisa poder
# verificar sem receber um segredo: certificados, atualizações
# de software, documentos jurídicos, commits assinados.

# ⚠ Compare tags em TEMPO CONSTANTE. Uma comparação comum para
# no primeiro byte diferente, e essa diferença de microssegundos
# permite ao atacante descobrir a tag byte a byte.
hmac.compare_digest(tag_recebida, tag_esperada)
Não-repúdio é a diferença que importa. Um HMAC prova que a mensagem veio de alguém que tem a chave — e como as duas partes têm a mesma chave, nenhuma delas pode provar a um juiz que foi a outra que gerou a etiqueta. Uma assinatura só pode ter sido produzida por quem detém a chave privada, então serve como prova diante de terceiros. É a razão de contratos, atualizações de software e certificados usarem assinatura, e não MAC.

Certificados X.509

# O problema que sobrou: como saber que ESTA chave pública é do
# meu banco, e não de um impostor? Assinatura não resolve sozinha —
# o impostor também sabe assinar, com a chave DELE.
#
# Resposta: alguém em quem você JÁ confia atesta a chave.
# Um certificado é isso: uma declaração assinada.

# Conteúdo de um certificado X.509:
#   Subject:      CN=exemplo.com.br        ← de quem é
#   SAN:          exemplo.com.br, www...   ← domínios cobertos
#   Public Key:   (a chave pública do site)
#   Issuer:       CN=GlobalTrust TLS CA G3 ← quem atesta
#   Validade:     2026-05-01 a 2026-07-30
#   Assinatura:   (do issuer, sobre tudo acima)

# A CADEIA DE CONFIANÇA:
#   certificado do site  ← assinado pela CA intermediária
#   CA intermediária     ← assinada pela CA raiz
#   CA raiz              ← autoassinada, JÁ INSTALADA na sua máquina
#
# A confiança termina (e começa) nas ~150 raízes que vieram com o
# seu sistema operacional e o seu navegador. Toda a segurança da
# web repousa sobre esse conjunto — e sobre a premissa de que
# nenhuma delas emitirá um certificado indevido.

# Inspecionando na prática:
openssl s_client -connect exemplo.com.br:443 -showcerts
openssl x509 -in cert.pem -text -noout

O que o navegador realmente verifica

# O que o navegador confere, em ordem, antes de mostrar o cadeado:
#
#  1. a assinatura de cada certificado bate com a chave pública
#     do certificado acima na cadeia?
#  2. a cadeia termina numa raiz que eu já tenho instalada?
#  3. a data de hoje está dentro da validade?
#  4. o domínio que pedi está na lista de nomes do certificado?
#  5. o certificado foi revogado? (OCSP / CRL — na prática, frágil)
#  6. ele aparece nos logs públicos de Certificate Transparency?
#
# Repare: NENHUMA dessas checagens, exceto a revogação, precisa de
# rede. A raiz já estava na máquina antes de a conexão existir.

# Os três níveis de validação, e o que eles realmente significam:
#   DV (Domain Validation)       — provou controlar o domínio.
#                                  É o que o Let's Encrypt emite,
#                                  de graça e automaticamente.
#   OV / EV (Organization/Extended) — a CA verificou documentos
#                                  da empresa. Os navegadores
#                                  pararam de exibir a barra verde:
#                                  estudos mostraram que ninguém
#                                  reparava, e ela dava falsa segurança.
#
# ⚠ O cadeado NÃO significa "site confiável". Significa
# "a conexão é cifrada e o domínio confere". Um site de phishing
# em banco-do-brasi1.com tem cadeado — e é um domínio legítimo,
# que ele de fato controla. O cadeado nunca prometeu honestidade.

# CERTIFICATE TRANSPARENCY: como se detecta emissão indevida.
# Toda CA precisa publicar cada certificado emitido num log público
# e append-only (uma árvore de Merkle, feita de hashes). Assim o
# dono de um domínio pode monitorar e descobrir se alguém emitiu
# um certificado para o site dele. Foi assim que se pegou a
# Symantec emitindo certificados de teste para domínios do Google.
④ Projeto para programar

Experimentando

Mini projeto: inspecione certificados de verdade. Rode openssl s_client -connect site:443 -showcerts para três sites diferentes e monte a cadeia de cada um: quem assinou quem, até qual raiz. Compare as validades — você vai notar que hoje quase todos duram 90 dias. Depois olhe a sua própria loja de raízes confiáveis e conte quantas autoridades, de quantos países, você está confiando sem nunca ter decidido isso.

Projeto principal: monte sua própria mini-PKI com OpenSSL. Crie uma CA raiz autoassinada, uma CA intermediária assinada pela raiz, e um certificado de servidor assinado pela intermediária. Suba um servidor HTTPS local com ele. Primeiro acesse sem instalar nada e veja o erro ERR_CERT_AUTHORITY_INVALID; depois instale sua raiz no sistema e veja o cadeado aparecer. Você acabou de executar, em miniatura, exatamente o que faz um proxy corporativo que inspeciona TLS — e de entender por que ele consegue.

Desafio extra: implemente uma árvore de Merkle e use-a como log append-only. Cada folha é o hash de uma entrada; cada nó interno é o hash dos dois filhos; a raiz resume tudo. Implemente a prova de inclusão: dado um item, devolva os poucos hashes (log n deles) que permitem a terceiros verificar que ele está no log, sem baixar o log inteiro. É exatamente o mecanismo do Certificate Transparency — e também o de blockchains e do git.

⑤ Exercícios rápidos

Teste sua intuição

O que uma assinatura digital garante?
Qual é a diferença essencial entre HMAC e assinatura digital?
Como o navegador decide que uma cadeia de certificados é confiável?
O que o cadeado do navegador realmente garante?
⑥ Aplicações no mundo real

Onde você encontra isso

📲

Assinatura de código

Todo aplicativo nas lojas da Apple e do Google é assinado, e o sistema recusa executar binários cuja assinatura não confere. Atualizações do Windows, pacotes do apt e imagens de container seguem o mesmo modelo. É a defesa central contra ataques à cadeia de suprimentos — e por isso a chave privada de assinatura de uma empresa é um dos ativos mais protegidos que ela tem, geralmente guardada num HSM que nunca a revela.

🆓

Let's Encrypt e a web cifrada por padrão

Em 2014, certificados custavam caro e exigiam processo manual; menos de 30% do tráfego web era HTTPS. O Let's Encrypt tornou a emissão gratuita e totalmente automática pelo protocolo ACME — seu servidor prova controlar o domínio respondendo a um desafio, e recebe o certificado em segundos. Hoje mais de 95% do tráfego é cifrado. É um dos casos mais claros de como remover atrito muda o comportamento de uma indústria inteira.

🚨

Quando uma CA falha

Em 2011 a DigiNotar, uma autoridade holandesa, foi invadida e emitiu certificados fraudulentos para domínios do Google, usados para interceptar o Gmail de usuários iranianos. A resposta foi remover a DigiNotar de todos os navegadores do mundo — e a empresa faliu em semanas. O episódio motivou diretamente a criação do Certificate Transparency, para que emissões indevidas passassem a ser detectáveis em vez de invisíveis.

← Anterior: Criptografia de chave pública Próxima: TLS e HTTPS →