Capa do Ebook gratuito Criptografia Aplicada para Profissionais: o que usar, quando e por quê

Criptografia Aplicada para Profissionais: o que usar, quando e por quê

Novo curso

22 páginas

Fundamentos de criptografia simétrica e critérios de escolha de algoritmos

Capítulo 2

Tempo estimado de leitura: 14 minutos

+ Exercício

Criptografia simétrica é a família de técnicas em que a mesma chave secreta é usada para cifrar e decifrar dados. Em termos práticos, isso significa que quem produz o dado protegido e quem o consome precisam compartilhar previamente (ou negociar de forma segura) esse segredo. A grande vantagem é desempenho: algoritmos simétricos modernos são extremamente rápidos e adequados para grandes volumes (arquivos, backups, bancos de dados, tráfego de rede). A principal implicação operacional é a gestão de chaves: como gerar, armazenar, rotacionar e limitar o acesso a esse segredo.

Ao escolher criptografia simétrica para um sistema, você normalmente está resolvendo um destes problemas: (1) confidencialidade de dados em repouso (disco, objeto, coluna, arquivo), (2) confidencialidade de dados em trânsito (após uma negociação de chaves, como em protocolos seguros), (3) integridade e autenticidade de mensagens (com MACs), ou (4) combinação de confidencialidade e integridade (com AEAD). Cada um desses usos tem critérios de escolha diferentes, e confundir “cifrar” com “autenticar” é uma fonte comum de falhas.

Conceitos essenciais: chave, cifra, modo e nonce

Chave simétrica

A chave é um valor secreto (por exemplo, 128 ou 256 bits) que parametriza o algoritmo. Para segurança prática, a chave deve ser gerada por um gerador criptograficamente seguro (CSPRNG) e tratada como material sensível: não deve aparecer em logs, não deve ser hardcoded, e deve ter controles de acesso e rotação. A força de uma cifra simétrica moderna depende principalmente do tamanho da chave e da robustez do algoritmo, mas na prática quase sempre o ponto fraco é o manuseio da chave.

Cifra de bloco vs cifra de fluxo

Há duas categorias principais:

  • Cifras de bloco (ex.: AES) transformam blocos de tamanho fixo (AES usa 128 bits). Para cifrar mensagens maiores, é necessário um modo de operação (CBC, CTR, GCM, XTS etc.).

    Continue em nosso aplicativo

    Você poderá ouvir o audiobook com a tela desligada, ganhar gratuitamente o certificado deste curso e ainda ter acesso a outros 5.000 cursos online gratuitos.

    ou continue lendo abaixo...
    Download App

    Baixar o aplicativo

  • Cifras de fluxo (ex.: ChaCha20) geram um fluxo pseudoaleatório que é combinado com o texto puro (tipicamente via XOR). Em geral, exigem um nonce único por chave para evitar reutilização do fluxo.

Na prática moderna, você frequentemente escolhe entre “AES em um modo seguro” ou “ChaCha20 em um modo autenticado”. A escolha não é apenas técnica: envolve suporte de hardware, bibliotecas disponíveis, requisitos de conformidade e risco de mau uso.

Nonce e IV: o que são e por que importam

Muitos esquemas simétricos exigem um valor não secreto adicional por mensagem, chamado IV (vetor de inicialização) ou nonce. Em vários modos, esse valor precisa ser único por chave (nunca repetir). Em outros, precisa ser imprevisível (aleatório). Repetir nonce/IV em modos como CTR, GCM ou ChaCha20-Poly1305 pode quebrar confidencialidade e/ou integridade de forma catastrófica. Por isso, a escolha do algoritmo deve considerar o quão fácil é garantir unicidade/aleatoriedade no seu ambiente (múltiplas instâncias, concorrência, reinícios, dispositivos embarcados, etc.).

O que a criptografia simétrica entrega (e o que não entrega)

Confidencialidade não implica integridade

Um erro recorrente é assumir que “cifrar” impede alterações. Muitos modos de cifra são maleáveis: um atacante pode modificar o ciphertext e induzir mudanças previsíveis no plaintext após a decifragem, sem necessariamente ser detectado. Para evitar isso, você precisa de autenticação (MAC) ou de um modo AEAD (Authenticated Encryption with Associated Data), que fornece confidencialidade e integridade em conjunto.

AEAD e dados associados (AAD)

AEAD (ex.: AES-GCM, ChaCha20-Poly1305) cifra o conteúdo e produz um tag de autenticação. Além disso, permite autenticar dados que não são cifrados, chamados AAD (por exemplo: cabeçalhos, IDs de registro, versão do protocolo, metadados). AAD é útil quando você precisa que certos campos permaneçam visíveis, mas não possam ser adulterados.

Critérios de escolha de algoritmos e modos

1) Prefira AEAD por padrão

Se você está protegendo mensagens, registros, objetos ou payloads, a recomendação prática é: use AEAD sempre que possível. Isso reduz a chance de erros de composição (por exemplo, “cifra e depois MAC” feito de forma incorreta). AEAD também simplifica APIs e testes: ou a verificação do tag passa e você obtém o plaintext, ou falha e você descarta.

  • AES-GCM: muito comum, rápido com aceleração de hardware (AES-NI e instruções relacionadas). Requer nonce único por chave (tipicamente 96 bits). É sensível a reutilização de nonce.

  • ChaCha20-Poly1305: excelente desempenho em CPUs sem aceleração AES e em ambientes móveis/embarcados. Também requer nonce único por chave (tipicamente 96 bits). Costuma ser mais “à prova de desempenho ruim” em hardware heterogêneo.

2) Considere o ambiente de execução e aceleração de hardware

Em servidores modernos, AES-GCM costuma ser extremamente rápido. Em dispositivos sem aceleração, ChaCha20-Poly1305 pode ser mais rápido e com consumo de energia menor. O critério aqui é operacional: latência, throughput e custo. Se você tem uma frota heterogênea (parte com AES-NI, parte sem), pode ser útil suportar ambos e negociar, ou padronizar em ChaCha20-Poly1305 para consistência.

3) Evite modos legados e armadilhas comuns

  • ECB: não use. Ele revela padrões porque blocos iguais geram ciphertexts iguais.

  • CBC: pode ser seguro quando bem implementado com IV aleatório e autenticação correta, mas é mais fácil errar (padding, oráculos de padding, composição com MAC). Se você precisa de confidencialidade + integridade, AEAD é preferível.

  • CTR: fornece confidencialidade, mas não integridade. Exige nonce/contador único por chave. Deve ser combinado com MAC (composição correta) ou substituído por AEAD.

4) Para dados em disco: XTS e alternativas

Para criptografia de disco/volume, o caso é diferente: você cifra setores/blocos com acesso aleatório e necessidade de “tweak” por setor. O modo clássico é AES-XTS. Ele é projetado para armazenamento e não fornece autenticação; portanto, não impede que dados cifrados sejam alterados (o que pode ser aceitável em alguns cenários de disco, mas não em registros de aplicação). Para arquivos/objetos em aplicações, AEAD costuma ser mais apropriado porque detecta adulteração.

5) Tamanho de chave: 128 vs 256 bits

Para a maioria dos sistemas, 128 bits já oferece margem de segurança muito alta. 256 bits pode ser escolhido por requisitos regulatórios, por padronização interna ou por necessidade de margem adicional contra avanços futuros. O custo de desempenho entre AES-128 e AES-256 pode variar; em alguns ambientes, AES-256 é um pouco mais lento. Em ChaCha20, a chave é tipicamente 256 bits.

Critério prático: se não há restrição, AES-128-GCM ou ChaCha20-Poly1305 são escolhas sólidas. Se sua organização exige 256 bits, use AES-256-GCM ou ChaCha20-Poly1305 (já é 256).

6) Gestão de nonce/IV: escolha que reduz risco de repetição

O melhor algoritmo não compensa um esquema de nonce frágil. Perguntas práticas para orientar a escolha:

  • Você consegue garantir unicidade global de nonce por chave em ambiente distribuído?

  • Você tem contadores persistentes (sobrevivem a reinício) ou precisa de nonces aleatórios?

  • Você cifra em múltiplas threads/processos simultâneos?

Se você optar por nonces determinísticos (contador), precisa garantir persistência e exclusão mútua. Se optar por nonces aleatórios, precisa de CSPRNG e de um tamanho de nonce que torne colisões negligenciáveis no volume esperado. Em GCM e ChaCha20-Poly1305, o padrão é 96 bits; nonces aleatórios de 96 bits são geralmente aceitáveis para muitos cenários, mas em volumes muito altos por chave pode ser preferível um esquema estruturado (por exemplo, prefixo por instância + contador).

7) Separação de chaves e derivação

Reutilizar a mesma chave para finalidades diferentes (cifrar e autenticar em construções não-AEAD, ou cifrar dois tipos de dados com requisitos distintos) aumenta risco de falhas e de interações inesperadas. Um critério de escolha importante é: sua biblioteca suporta derivação de chaves de forma simples (por exemplo, via HKDF) para obter chaves independentes por contexto?

Mesmo usando AEAD, é comum derivar chaves por “contexto” (por exemplo, por usuário, por tenant, por tipo de dado, por versão do esquema). Isso facilita rotação e limita o impacto de um vazamento.

Passo a passo prático: cifrar e autenticar um payload com AEAD

A seguir está um fluxo prático, aplicável a APIs, filas, eventos e armazenamento de objetos. O objetivo é produzir um pacote que possa ser armazenado/transmitido e depois verificado/decifrado com segurança.

Passo 1: defina o formato do pacote

Um formato típico inclui:

  • alg: identificador do algoritmo (ex.: AES-256-GCM).

  • kid: identificador da chave (para rotação).

  • nonce: valor único por mensagem.

  • aad: metadados autenticados (podem ficar fora do ciphertext).

  • ciphertext: dados cifrados.

  • tag: autenticação (às vezes embutida no ciphertext conforme a API).

Decisão importante: o nonce não precisa ser secreto, mas precisa ser transmitido/armazenado junto com o ciphertext para permitir decifragem.

Passo 2: escolha e construa o AAD

Selecione campos que devem ser protegidos contra alteração, mas não precisam ser escondidos. Exemplos: ID do usuário, ID do registro, versão do esquema, tipo do evento, timestamp truncado, nome do campo. O AAD deve ser serializado de forma determinística (por exemplo, JSON canônico, CBOR, ou uma concatenação com delimitadores bem definidos) para evitar ambiguidades.

Passo 3: gere o nonce com estratégia segura

Estratégias comuns:

  • Nonce aleatório (96 bits): simples, exige CSPRNG. Bom para muitos casos com volume moderado por chave.

  • Nonce estruturado: prefixo fixo por instância (ex.: 32 bits) + contador (ex.: 64 bits). Bom para alto volume e para reduzir chance de colisão, desde que o contador seja persistente e nunca reinicie para a mesma chave.

Se você não consegue garantir unicidade, reavalie o design: por exemplo, reduzir o volume por chave (rotacionar mais), ou usar uma construção que lide melhor com seu modelo operacional (ainda assim, em AEAD moderno, unicidade é regra).

Passo 4: cifre com AEAD e obtenha ciphertext + tag

O processo lógico é:

  • Entrada: chave simétrica, nonce, plaintext, AAD.

  • Saída: ciphertext e tag.

Em muitas bibliotecas, a função de “encrypt” já retorna ciphertext com tag anexado. Em outras, retorna separadamente. Trate o tag como parte essencial do pacote.

// Pseudocódigo (independente de linguagem) para AEAD encrypt: key = obter_chave_por_kid(kid) nonce = gerar_nonce_unico() aad = serializar_metadados({versao, user_id, record_id}) (ciphertext, tag) = AEAD_Encrypt(alg, key, nonce, plaintext, aad) pacote = { alg, kid, nonce, aad, ciphertext, tag } armazenar_ou_transmitir(pacote)

Passo 5: decifre validando o tag antes de usar o plaintext

Na decifragem, a regra é: se a verificação falhar, descarte. Não tente “recuperar parcialmente” dados. Não diferencie mensagens de erro de forma que vaze informação (por exemplo, “tag inválido” vs “padding inválido” em esquemas antigos). Em AEAD, a API normalmente retorna sucesso/falha.

// Pseudocódigo para AEAD decrypt: pacote = ler_pacote() key = obter_chave_por_kid(pacote.kid) plaintext = AEAD_Decrypt( pacote.alg, key, pacote.nonce, pacote.ciphertext, pacote.aad, pacote.tag ) if falhou: rejeitar() else: processar(plaintext)

Passo 6: registre e monitore sem vazar segredo

Para observabilidade, registre kid, algoritmo, tamanho do payload, e talvez um identificador do pacote. Não registre plaintext, chave, nem material derivado sensível. Falhas de autenticação podem indicar corrupção, bugs de serialização do AAD, nonces repetidos ou tentativas de adulteração; monitore taxa de falhas e investigue picos.

Passo a passo prático: criptografia de arquivo/objeto com streaming

Para arquivos grandes, você frequentemente precisa de cifragem em streaming e, ao mesmo tempo, integridade. Uma abordagem comum é dividir em chunks e usar AEAD por chunk, com nonces derivados de um contador.

Passo 1: defina tamanho de chunk e metadados

Escolha um tamanho (ex.: 1 MiB) equilibrando overhead e paralelismo. Metadados autenticados podem incluir: ID do arquivo, índice do chunk, tamanho total, versão do esquema.

Passo 2: derive uma chave por arquivo (opcional, recomendado)

Em vez de usar diretamente uma chave mestra para todos os arquivos, derive uma chave por arquivo usando um KDF (por exemplo, HKDF) com um salt aleatório e info contendo o ID do arquivo. Isso limita impacto de vazamento e facilita rotação.

Passo 3: nonce por chunk

Use um nonce estruturado: prefixo aleatório por arquivo + contador do chunk. Assim, cada chunk tem nonce único sem depender de RNG a cada bloco.

Passo 4: cifre chunk a chunk com AEAD

// Pseudocódigo de alto nível: file_key = HKDF(master_key, salt=file_salt, info=file_id) prefix = random(32 bits) for i in 0..N-1: nonce = prefix || uint64_be(i) aad = {file_id, chunk_index=i, versao} (c, tag) = AEAD_Encrypt(file_key, nonce, chunk_plain, aad) gravar({nonce, aad, c, tag})

Na leitura, você reexecuta a derivação da chave do arquivo, reconstrói o nonce por chunk (ou lê do pacote), valida o tag e só então entrega o chunk ao consumidor. Esse padrão evita que uma alteração em um chunk passe despercebida.

MACs simétricos: quando usar e como escolher

Há cenários em que você não precisa de confidencialidade, apenas de integridade/autenticidade (por exemplo, validar que um payload não foi alterado, mas ele pode ser público). Nesse caso, um MAC é apropriado. Opções comuns:

  • HMAC (ex.: HMAC-SHA-256): robusto, amplamente disponível, fácil de usar. Requer uma chave secreta.

  • CMAC (baseado em AES): útil quando você já depende de AES e quer um MAC padronizado com cifra de bloco.

Critérios de escolha: disponibilidade na biblioteca, facilidade de rotação de chaves, e consistência com o restante do sistema. Evite “MAC caseiro” (por exemplo, hash simples com chave concatenada) e evite comparar tags com comparação não constante (timing leaks) quando isso for relevante.

Erros de implementação que influenciam a escolha

Reutilização de nonce

Se seu sistema tem risco de reinício frequente, múltiplas instâncias e contadores não persistentes, a chance de repetir nonce aumenta. Nesse caso, a escolha do algoritmo deve vir acompanhada de um design de nonce robusto (prefixo por instância, contador persistente, ou rotação de chave agressiva). Não trate nonce como “detalhe”; ele é parte do segredo operacional.

Serialização ambígua de AAD

Se AAD for montado com concatenação simples sem delimitadores, diferentes conjuntos de campos podem gerar a mesma sequência de bytes, causando validações incorretas. Prefira formatos determinísticos e versionados. Inclua um campo de versão no AAD para permitir evolução do esquema.

Uso incorreto de compressão antes de cifrar

Comprimir antes de cifrar pode vazar informação em alguns cenários interativos quando o atacante influencia parte do plaintext e observa tamanhos. Se você precisa compressão, avalie se o contexto permite esse risco e, quando possível, use padding de tamanho ou evite compressão em dados sensíveis influenciáveis externamente.

Rotação de chaves sem kid

Sem um identificador de chave no pacote, a rotação vira tentativa e erro (testar várias chaves até uma funcionar), o que é custoso e pode abrir espaço para comportamentos inesperados. Um critério de escolha de biblioteca/formato é suportar kid e múltiplas chaves ativas (uma para cifrar, várias para decifrar durante a janela de transição).

Checklist de decisão rápida

  • Precisa de confidencialidade e integridade? Use AEAD (AES-GCM ou ChaCha20-Poly1305).

  • Ambiente sem aceleração AES ou com performance imprevisível? Considere ChaCha20-Poly1305.

  • Dados em disco por setor? Considere AES-XTS (e entenda que não autentica).

  • Somente integridade/autenticidade? Use HMAC-SHA-256 (ou CMAC quando fizer sentido).

  • Consegue garantir nonce único por chave? Se não, redesenhe o esquema (prefixo+contador, rotação, limites por chave).

  • Formato versionado e AAD determinístico? Planeje isso antes de colocar em produção.

Agora responda o exercício sobre o conteúdo:

Ao proteger um payload com criptografia simétrica, qual abordagem reduz o risco de falhas por composição incorreta entre confidencialidade e integridade?

Você acertou! Parabéns, agora siga para a próxima página

Você errou! Tente novamente.

AEAD entrega confidencialidade e integridade juntas: ao decifrar, o sistema só aceita o plaintext se o tag for válido. Isso evita erros comuns de compor cifra e MAC de forma incorreta e reduz riscos de maleabilidade.

Próximo capitúlo

Modos de operação e criptografia autenticada para evitar erros de implementação

Arrow Right Icon
Baixe o app para ganhar Certificação grátis e ouvir os cursos em background, mesmo com a tela desligada.