Pular para o conteúdo
ecdsa.com

AES-GCM vs ChaCha20-Poly1305: qual AEAD usar

Os dois são AEADs padronizados com tag de 128 bits e nonces de 96 bits. O AES-GCM vence em CPUs com instruções AES e em ambientes FIPS; o ChaCha20-Poly1305 vence em todos os outros casos.
Itens comparadosAES-GCMChaCha20-Poly1305

AES-GCM vs ChaCha20-Poly1305 é a escolha entre os dois algoritmos de criptografia autenticada que transportam quase todo o tráfego criptografado: TLS 1.3, QUIC, SSH, WireGuard, age e a maior parte da criptografia na camada de aplicação. Os dois são seguros quando usados corretamente, os dois falham de forma grave quando um nonce se repete, e a velocidade de ambos depende muito do hardware.

Visão geral

AES-GCMChaCha20-Poly1305
EspecificaçãoNIST SP 800-38D (2007)RFC 8439 (2018, substitui a RFC 7539)
Tamanhos de chave128, 192, 256 bits256 bits
Nonce96 bits (recomendado)96 bits (192 bits no XChaCha20)
Tag128 bits (tags mais curtas são permitidas, mas não recomendadas)128 bits
Máximo de dados por mensagemcerca de 64 GiB (2³² − 2 blocos)256 GiB (2³² blocos de 64 bytes)
Limite de nonces aleatórios por chave2³² mensagens (SP 800-38D)Mesma ordem de grandeza com nonces de 96 bits; praticamente ilimitado com XChaCha20
Reutilização de nonceVaza o XOR dos textos claros e a chave do GHASH, o que permite falsificaçõesVaza o XOR dos textos claros e permite falsificações
Vazão, 16 KiB, OpenSSL 3.6.510,4 GB/s (AES-128), 8,8 GB/s (AES-256)2,1 GB/s
Vazão, mensagens de 16 bytes0,14 GB/s (AES-256)0,52 GB/s
Tempo constante sem hardwareDifícil (o AES baseado em tabelas vaza informação pelo cache)Natural (adição, rotação, XOR)
Aprovado no FIPS 140-3SimNão
TLS 1.3TLS_AES_128_GCM_SHA256 (obrigatória), TLS_AES_256_GCM_SHA384 (recomendada)TLS_CHACHA20_POLY1305_SHA256 (recomendada)
Outros usosJWE A128GCM e A256GCM, IPsec, SSH aes256-gcm@openssh.com, criptografia de disco e na nuvemWireGuard, SSH chacha20-poly1305@openssh.com, age, libsodium

Vazão medida com openssl speed -evp em um núcleo de um Apple M4 Max, que tem instruções de AES e de multiplicação polinomial.

O desempenho depende da CPU

O AES-GCM foi feito para o hardware: as rodadas do AES são executadas como instruções únicas (AES-NI no x86, as extensões de criptografia do ARMv8) e o GHASH usa multiplicação sem carry. Com os dois recursos disponíveis, ele chega a uns 10 GB/s por núcleo nesta medição, cerca de cinco vezes a vazão do ChaCha20-Poly1305. Sem eles, o AES precisa usar tabelas de consulta, que são lentas e vazam bits da chave pelo tempo de acesso ao cache, ou código bitsliced, que é de tempo constante, mas lento. O ChaCha20 só precisa de adições, rotações e XORs de 32 bits, por isso roda rápido e em tempo constante em qualquer CPU, inclusive em celulares de entrada e microcontroladores.

Mensagens pequenas reduzem ou invertem a diferença: com entradas de 16 bytes, o ChaCha20-Poly1305 chegou a 0,52 GB/s, contra 0,14 GB/s do AES-256-GCM, porque o custo de preparação do GCM domina. Para registros TLS típicos (até 16 KiB) em servidores, o AES-GCM é mais rápido; com muitos pacotes minúsculos, a diferença é pequena, seja qual for o mais rápido.

Nonces e limites

Os dois são cifras em modo contador com autenticadores de uso único, por isso o par (chave, nonce) nunca deve se repetir. Uma repetição revela o XOR dos dois textos claros; no GCM, ela também permite que um atacante recupere a subchave de autenticação e falsifique mensagens com essa chave, e no Poly1305 ela expõe a chave de uso único e permite falsificação para aquele nonce. A NIST SP 800-38D limita os IVs de 96 bits gerados aleatoriamente a 2³² invocações por chave, para manter a probabilidade de colisão desprezível; o TLS contorna o problema derivando os nonces dos números de sequência dos registros e renovando as chaves.

Se seu projeto gera nonces aleatórios para muitas mensagens com a mesma chave, use uma construção com mais espaço de nonce ou com resistência a uso indevido (misuse resistance):

  • XChaCha20-Poly1305 (nonces de 192 bits, descrito em um Internet-Draft do IRTF e implementado pela libsodium e por outras bibliotecas), em que nonces aleatórios são seguros para uma quantidade praticamente ilimitada de mensagens;
  • AES-GCM-SIV (RFC 8452), em que a reutilização de nonce revela apenas se duas mensagens eram idênticas;
  • ou derivação de chave por mensagem ou por sessão, como fazem o TLS, o age e o HPKE.

Nenhum dos dois algoritmos vincula o texto cifrado à chave (não há key commitment): é possível montar um texto cifrado que se descriptografa de forma válida com duas chaves diferentes, o que importa em projetos com vários destinatários ou baseados em senha (o problema das “invisible salamanders”). Acrescente um mecanismo de key commitment se atacantes puderem escolher as chaves.

Node.js 26: a mesma interface AEAD para os dois algoritmos
import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";

const plaintext = Buffer.from("card ending 4242, amount 19.99");
const aad = Buffer.from("order=7781");

for (const algorithm of ["aes-256-gcm", "chacha20-poly1305"]) {
  const key = randomBytes(32);
  const nonce = randomBytes(12); // 96-bit nonce for both; never reuse with the same key
  const cipher = createCipheriv(algorithm, key, nonce, { authTagLength: 16 });
  cipher.setAAD(aad);
  const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
  const tag = cipher.getAuthTag();

  const decipher = createDecipheriv(algorithm, key, nonce, { authTagLength: 16 });
  decipher.setAAD(aad);
  decipher.setAuthTag(tag);
  const roundTrip = Buffer.concat([decipher.update(ciphertext), decipher.final()]);

  console.log(algorithm.padEnd(18), "ciphertext", ciphertext.length, "bytes + tag", tag.length, "bytes, decrypts:", roundTrip.equals(plaintext));
}
Saída
aes-256-gcm        ciphertext 30 bytes + tag 16 bytes, decrypts: true
chacha20-poly1305  ciphertext 30 bytes + tag 16 bytes, decrypts: true

Como o TLS escolhe entre os dois

O TLS 1.3 exige que toda implementação ofereça suporte a TLS_AES_128_GCM_SHA256 e recomenda o AES-256-GCM e o ChaCha20-Poly1305. Clientes sem hardware de AES colocam o ChaCha20 em primeiro lugar na lista; servidores que respeitam essa preferência entregam a cada cliente a cifra mais rápida para ele. O OpenSSL implementa isso com a opção PrioritizeChaCha (SSL_OP_PRIORITIZE_CHACHA), que prefere o ChaCha20 apenas quando o cliente o listou primeiro, e o BoringSSL usa grupos de preferência igual com o mesmo objetivo. O gerador de configurações TLS produz configurações de servidor que mantêm as duas cipher suites.

Quando escolher cada um

  • Servidores TLS e QUIC: habilite os dois; prefira o AES-GCM, mas deixe que os clientes que colocam o ChaCha20 em primeiro lugar o recebam.
  • Ambientes FIPS 140-3: AES-GCM; o ChaCha20-Poly1305 não é um algoritmo aprovado.
  • Dispositivos móveis, IoT e microcontroladores sem aceleração de AES: ChaCha20-Poly1305.
  • Criptografia na camada de aplicação com nonces aleatórios e chaves de longa duração: XChaCha20-Poly1305 ou AES-GCM-SIV.
  • JWE: A256GCM (ou A128GCM); o ChaCha20 não está no registro principal do JWA.
  • Mensagens únicas muito grandes (acima de 64 GiB): divida-as em segmentos com um nonce por segmento (como o age faz com segmentos de 64 KiB de ChaCha20-Poly1305); não conte com os limites por mensagem.

Notas de migração

Em um sistema bem projetado, trocar de AEAD muda o formato do texto cifrado e nada mais.

  1. Versione o formato: armazene um identificador do algoritmo e um identificador da chave com cada texto cifrado, para que os dados antigos continuem legíveis.
  2. Use uma chave separada por algoritmo: derive chaves distintas (por exemplo, com HKDF e strings info diferentes) em vez de reutilizar a mesma chave nos dois.
  3. Revise a geração de nonces: os contadores precisam ser gravados de forma persistente, para sobreviver a reinicializações; com nonces aleatórios, é preciso ficar dentro dos limites acima ou migrar para o XChaCha20.
  4. Recriptografe sob demanda: descriptografe com o algoritmo antigo e grave com o novo quando os registros forem acessados, a menos que um prazo de conformidade exija uma migração em massa.
  5. Meça o desempenho no hardware real: a ordem de velocidade se inverte entre CPUs de servidor e dispositivos pequenos.

Referências

Todas as comparações