Trilha 13 · Segurança e criptografia

Criptografia simétrica

Uma chave, duas pessoas, e a mesma operação para fechar e abrir. É a forma mais antiga de criptografia e continua sendo a que faz o trabalho pesado: todo byte que trafega no seu HTTPS é protegido por uma cifra simétrica. Esta lição mostra como ela funciona, e por que a parte que quase ninguém pensa — o modo de operação — decide se ela protege alguma coisa.

① Intuição

O cadeado com uma chave só

Você tranca uma caixa com um cadeado e manda para um amigo. Se ele tem uma cópia da mesma chave, abre. É simétrico: a mesma chave fecha e abre, e todo mundo que tem a chave pode fazer as duas coisas. Simples, rápido, eficiente — e com um problema óbvio embutido: como o seu amigo recebeu a cópia da chave?

Por milênios essa pergunta não teve boa resposta. Era preciso um encontro presencial, um mensageiro de confiança, uma mala diplomática. Para um exército, viável. Para dois computadores que nunca se viram e precisam conversar em 100 milissegundos, impossível. Guarde essa pergunta: ela é o assunto exato da próxima lição.

O princípio de Kerckhoffs, de 1883, e ainda a regra. A segurança de um sistema deve depender apenas do segredo da chave — nunca do segredo do algoritmo. Algoritmos vazam, são desmontados por engenharia reversa e acabam publicados; chaves podem ser trocadas. Por isso AES, SHA-256 e TLS são públicos e escrutinados por milhares de pesquisadores há décadas. Um fornecedor que promete segurança porque "nosso algoritmo é proprietário" está descrevendo a fraqueza como se fosse a força.
② Visualização interativa

XOR, reúso de chave e o cadeado do ECB

Na primeira aba, cifre um texto com XOR e veja a mesma operação desfazê-lo — depois descubra o que acontece quando a chave é reutilizada. Na segunda, cifre uma imagem em ECB e em CBC: é a demonstração clássica de que uma cifra forte no modo errado não esconde nada.

A operação mais simples que existe em criptografia: XOR. Ela é sua própria inversa — aplicar a mesma chave duas vezes devolve o original. Toda cifra simétrica moderna é, no fundo, uma forma sofisticada de gerar bits pseudoaleatórios e fazer XOR com eles.

MENSAGEM
CHAVE
CIFRADO — mensagem ⊕ chave (repetida)
0d 1d 0c 02 0e 1e 69 0c 0e 6f 0d 04 0c 0f 07 09 0a 08 13
DECIFRADO — cifrado ⊕ chave (a MESMA operação)
ATACAR AO AMANHECER
A = 01000001  ⊕  L = 01001100  =  00001101
00001101  ⊕  L = 01001100  =  01000001 = A de volta.
Se a chave fosse verdadeiramente aleatória, do tamanho da mensagem e usada uma única vez, isto seria o one-time pad — a única cifra com segurança perfeita comprovada matematicamente.
③ Explicação técnica

XOR e o one-time pad

# XOR: a operação que sustenta toda cifra simétrica.
#   0 ⊕ 0 = 0     1 ⊕ 0 = 1
#   0 ⊕ 1 = 1     1 ⊕ 1 = 0
#
# É sua própria inversa: (m ⊕ k) ⊕ k = m

def cifrar(msg, chave):
    return bytes(b ^ chave[i % len(chave)] for i, b in enumerate(msg))

# decifrar é a MESMA função — essa simetria dá nome à família

# ONE-TIME PAD: o caso perfeito, e por que é impraticável.
# Se a chave for (1) verdadeiramente aleatória, (2) do tamanho da
# mensagem e (3) usada UMA única vez, a cifra é matematicamente
# inquebrável — Shannon provou isso em 1949.
#
# Intuição da prova: para um texto cifrado de 20 bytes, EXISTE uma
# chave que o transforma em "ATACAR AO AMANHECER" e OUTRA que o
# transforma em "RECUAR PARA O SUL". Todas as mensagens do tamanho
# certo continuam igualmente plausíveis. O texto cifrado não carrega
# NENHUMA informação sobre a mensagem.
#
# O problema: se você consegue entregar em segredo uma chave do
# tamanho da mensagem, poderia ter entregado a mensagem. O one-time
# pad não resolve o problema — ele o move para a distribuição da chave.

# ⚠ E "one-time" é literal. Reutilizar a chave destrói tudo:
#   C1 ⊕ C2 = (M1 ⊕ K) ⊕ (M2 ⊕ K) = M1 ⊕ M2
#   A chave se cancela e sobra a relação entre as mensagens.
#   Foi assim que o projeto VENONA leu telegramas soviéticos por anos.

AES: o padrão

# AES (2001) — o padrão do mundo. Uma cifra de BLOCO:
# transforma 16 bytes de entrada em 16 bytes de saída, com a chave.
#
# Cada rodada aplica quatro passos, repetidos 10 a 14 vezes:
#   SubBytes    — troca cada byte por outro, via tabela (não-linear)
#   ShiftRows   — desloca as linhas do bloco (difusão horizontal)
#   MixColumns  — mistura as colunas (difusão vertical)
#   AddRoundKey — XOR com uma chave derivada daquela rodada
#
# O objetivo declarado é CONFUSÃO (esconder a relação chave→saída)
# e DIFUSÃO (espalhar cada bit de entrada por toda a saída) — os
# dois princípios que Shannon definiu em 1945 e continuam valendo.

# Tamanhos de chave: 128, 192 ou 256 bits.
# AES-128 já é inquebrável por força bruta: 2^128 tentativas.
# Para comparar, o universo tem ~2^58 segundos de idade.
# AES-256 é usado por margem extra (e contra ataques quânticos,
# que via algoritmo de Grover reduzem 2^256 para 2^128 — ainda seguro).

# Na prática, o AES roda em HARDWARE: as instruções AES-NI dos
# processadores modernos cifram vários gigabytes por segundo por
# núcleo. É por isso que HTTPS praticamente não custa desempenho hoje.
Cifra de bloco ou de fluxo? Cifras de bloco (AES) processam pedaços de tamanho fixo e precisam de preenchimento quando a mensagem não é múltipla do bloco. Cifras de fluxo (ChaCha20) geram uma sequência pseudoaleatória do tamanho exato da mensagem e fazem XOR — sem preenchimento. Na prática a fronteira sumiu: o modo CTR transforma o AES numa cifra de fluxo, e é assim que ele é usado quase sempre.

Modos de operação

# O AES cifra 16 bytes. E se a mensagem tiver 10 MB?
# O MODO DE OPERAÇÃO decide como encadear os blocos — e essa
# escolha importa tanto quanto a cifra em si.

# ECB (Electronic Codebook) — NUNCA USE
#   C[i] = E(K, M[i])           cada bloco independente
#   Blocos iguais → saídas iguais → a ESTRUTURA vaza.
#   É o "pinguim do ECB": a imagem cifrada continua reconhecível.

# CBC (Cipher Block Chaining)
#   C[i] = E(K, M[i] ⊕ C[i-1])   e C[-1] = IV aleatório
#   Esconde padrões, mas: não detecta adulteração, é sequencial
#   (não paraleliza) e o preenchimento abre a porta para os
#   ataques de padding oracle.

# CTR (Counter)
#   C[i] = M[i] ⊕ E(K, nonce || i)
#   Vira uma cifra de fluxo: paralelizável, sem preenchimento.
#   Mas continua sem autenticação.

# GCM = CTR + autenticação  ← USE ESTE
#   Cifra E produz uma etiqueta que denuncia qualquer bit alterado.

from cryptography.hazmat.primitives.ciphers.aead import AESGCM
chave = AESGCM.generate_key(bit_length=256)
aes = AESGCM(chave)
nonce = os.urandom(12)                   # NUNCA repita com a mesma chave
ct = aes.encrypt(nonce, mensagem, dados_associados)
pt = aes.decrypt(nonce, ct, dados_associados) # levanta exceção se adulterado

# ChaCha20-Poly1305 é a alternativa: mesma garantia, mais rápido
# em hardware sem aceleração de AES (celulares mais simples, IoT).

Por que autenticar é obrigatório

# Por que cifrar SEM autenticar é um erro?
#
# Sem autenticação, o atacante não lê a mensagem — mas pode
# MODIFICÁ-LA de formas previsíveis. Em CTR/OTP, inverter um bit
# do texto cifrado inverte exatamente o bit correspondente do
# texto claro. Ele não sabe o conteúdo, mas sabe a POSIÇÃO:
#
#   "TRANSFERIR 0100 PARA CONTA 7"
#                ^^ inverta estes bits sem conhecer a chave
#   "TRANSFERIR 9100 PARA CONTA 7"
#
# E o PADDING ORACLE: se o servidor responde de forma diferente
# para "preenchimento inválido" e "dados inválidos", o atacante
# usa essa diferença como um oráculo e decifra a mensagem INTEIRA,
# byte a byte, sem jamais descobrir a chave. Foi assim que caíram
# o ASP.NET (2010) e o próprio TLS 1.0 (ataques BEAST e Lucky 13).

# A regra: SEMPRE use AEAD (Authenticated Encryption with
# Associated Data). AES-GCM ou ChaCha20-Poly1305.
# Nunca componha "cifrar" e "autenticar" à mão — a ordem importa
# (encrypt-then-MAC é a única segura) e é fácil errar.

# E a regra que engloba todas: NÃO IMPLEMENTE CRIPTOGRAFIA.
# Use libsodium, a lib "cryptography" do Python, a Web Crypto API.
# Código criptográfico correto na teoria ainda vaza a chave por
# canais laterais: tempo de execução, cache, consumo de energia.
# Bibliotecas maduras foram auditadas contra isso; seu código não.
④ Projeto para programar

Experimentando

Mini projeto: reproduza o pinguim do ECB com uma imagem de verdade. Abra um BMP ou PPM (formatos sem compressão, para que os bytes correspondam a pixels), cifre o corpo do arquivo com AES-ECB preservando o cabeçalho, e abra o resultado num visualizador. Depois faça o mesmo com AES-CBC. A diferença entre as duas imagens é o argumento mais convincente que existe sobre modos de operação.

Projeto principal: quebre um XOR de chave repetida — a cifra de Vigenère, em bytes. Dado um texto cifrado longo, descubra o tamanho da chave (dica: a distância de Hamming normalizada entre blocos é mínima no tamanho correto), separe os bytes por posição da chave e resolva cada grupo como uma cifra de César, usando a frequência de letras do português. É o desafio clássico do Cryptopals, e ensina mais sobre por que criptografia caseira falha do que qualquer texto.

Desafio extra: implemente um bit-flipping attack contra AES-CTR sem autenticação. Cifre a string "usuario=joao;admin=false", e então — sem conhecer a chave — modifique o texto cifrado para que ele decifre como admin=true. Você só precisa saber a posição dos bytes e fazer XOR com a diferença desejada. Depois refaça tudo com AES-GCM e veja a decifração falhar com exceção. É a demonstração mais direta de por que AEAD não é opcional.

⑤ Exercícios rápidos

Teste sua intuição

Por que uma imagem cifrada em modo ECB continua reconhecível?
O que acontece se a mesma chave de one-time pad for usada em duas mensagens?
O que uma cifra AEAD (como AES-GCM) oferece além de confidencialidade?
O que diz o princípio de Kerckhoffs?
⑥ Aplicações no mundo real

Onde você encontra isso

💽

Criptografia de disco

BitLocker, FileVault e LUKS cifram o disco inteiro com AES, tipicamente em modo XTS — projetado especificamente para armazenamento, onde é preciso poder ler e escrever qualquer setor sem tocar nos outros. A chave fica protegida pelo TPM, um chip que só a libera se a máquina iniciar com a configuração esperada, o que impede alguém de simplesmente retirar o disco e lê-lo em outro computador.

💬

Mensagens fim a fim

Signal e WhatsApp cifram cada mensagem com uma chave simétrica diferente, derivada pelo Double Ratchet — um esquema que avança as chaves a cada mensagem. O efeito é notável: comprometer o aparelho hoje não revela as mensagens de ontem (forward secrecy) nem as de amanhã (post-compromise security). A criptografia assimétrica só aparece no estabelecimento inicial.

📼

Onde a criptografia caseira falhou

O CSS dos DVDs usava chave de 40 bits e caiu em 1999 num programa de poucas linhas. O WEP do Wi-Fi reutilizava IVs de 24 bits e podia ser quebrado em minutos. O A5/1 do GSM foi quebrado com tabelas pré-computadas. Todos foram desenhados em sigilo, sem revisão pública — exatamente o que o princípio de Kerckhoffs adverte, aprendido de novo a cada década.

← Anterior: Funções hash Próxima: Criptografia de chave pública →