Funções de derivação de chaves: PBKDF2, Argon2 e scrypt comparados
Compare funções de derivação de chaves para encriptação baseada em palavra-passe. Pontos fortes de PBKDF2, Argon2 e scrypt para aplicações de transferência segura de ficheiros.
Para chaves de encriptação derivadas de palavra-passe em 2026, o Argon2id é a escolha recomendada (vencedor do PHC, preferência da OWASP, defendido activamente contra atacantes com GPU e ASIC), o scrypt é uma segunda opção sólida (memory-hard, amplamente utilizado em criptomoedas), e o PBKDF2-SHA-256 com 600.000+ iterações permanece aceitável por compatibilidade mas oferece resistência mínima a GPU. Para aplicações de transferência de ficheiros onde os utilizadores introduzem uma palavra-passe para proteger um ficheiro partilhado, o Argon2id com 3 iterações, 64 MiB de memória e paralelismo de 4 é a linha de base moderna. O PBKDF2 sobrevive porque está integrado na Web Crypto API e não requer dependência WASM. Eis como os três diferem e quando cada um faz sentido.
Tabela comparativa
| Propriedade | PBKDF2 | scrypt | Argon2id | |---|---|---|---| | Ano de introdução | 2000 (RFC 2898) | 2009 (RFC 7914) | 2015 (vencedor PHC) | | Memory-hard | Não | Sim | Sim | | Flexibilidade de parâmetros | Apenas iterações | N, r, p | tempo, memória, paralelismo | | Resistência a GPU | Fraca | Moderada | Forte | | Resistência a ASIC | Muito fraca | Moderada | Forte | | Nativo no navegador (Web Crypto) | Sim | Não | Não | | Recomendação OWASP 2024 | Fallback aceitável | Aceitável | Preferido | | Custo típico no navegador (hardware moderno) | 600.000 iter = ~500 ms | N=2^17 = ~800 ms | 3 iter, 64 MiB = ~1 s |
Por que o memory-hard é importante
O modelo de ameaça para encriptação baseada em palavra-passe é a força bruta offline. Um atacante obtém o texto cifrado mais o salt, percorre um dicionário de palavras-passe, e tenta derivar uma chave que desencripte com sucesso. A defesa é tornar cada tentativa cara.
O PBKDF2 torna cada tentativa cara apenas em tempo de CPU (iterações SHA-256). As GPUs modernas executam milhares de milhões de operações SHA-256 por segundo; uma GPU de gaming pode testar 10-100 milhões de hipóteses PBKDF2-SHA-256-600000 por dia. Os atacantes com ASIC fazem várias ordens de grandeza melhor.
As funções memory-hard (scrypt, Argon2) requerem uma quantidade fixa de memória por tentativa. As GPUs e ASICs têm largura de banda de memória limitada, por isso o paralelismo por dispositivo é limitado. Um requisito de 64 MiB significa que uma GPU com 16 GB de VRAM pode executar no máximo 256 hipóteses paralelas, não milhões. O custo económico da força bruta aumenta 2-3 ordens de grandeza.
PBKDF2: o padrão legado
O PBKDF2 (RFC 2898) itera uma função pseudo-aleatória, tipicamente HMAC-SHA-256 ou HMAC-SHA-512, sobre a palavra-passe e o salt. O número de iterações é o único parâmetro ajustável.
const passwordKey = await crypto.subtle.importKey(
"raw", new TextEncoder().encode(password),
"PBKDF2", false, ["deriveKey"]
);
const aesKey = await crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt, // 16 bytes aleatórios
iterations: 600000,
hash: "SHA-256",
},
passwordKey,
{ name: "AES-GCM", length: 256 },
false,
["encrypt", "decrypt"]
);
A OWASP 2023 recomenda no mínimo 600.000 iterações de PBKDF2-SHA-256. O NIST SP 800-132 é mais antigo e menos específico. Algumas especificações (por exemplo, o padrão de 100.100 iterações do LastPass em 2018) são consideradas demasiado baixas em 2026.
Vantagens: integrado na Web Crypto, sem WASM, validado FIPS, suportado na retomada de sessão TLS 1.3, funciona em Node e navegadores de forma idêntica.
Limitações: sem resistência de memória, vulnerável à aceleração por GPU e ASIC. Duplicar as iterações duplica o custo do atacante mas também duplica o custo do utilizador legítimo. A certo ponto os utilizadores recusam esperar e impõe-se um limite às iterações.
scrypt: o primeiro deployment memory-hard
O scrypt (RFC 7914) foi inventado por Colin Percival em 2009 para o Tarsnap. Mistura material da palavra-passe através de um grande buffer de memória, forçando o atacante a manter esse buffer durante cada hipótese.
Três parâmetros:
- N: factor de custo (tipicamente 2^14 a 2^20). O uso de memória é aproximadamente 128 * N * r bytes.
- r: tamanho do bloco (tipicamente 8). Afecta a memória e a contagem de iterações GHASH.
- p: paralelização (tipicamente 1). Valores mais altos aceleram a computação legítima mas também aceleram os atacantes; normalmente deixe em 1.
A OWASP recomenda N=2^17, r=8, p=1 como linha de base, que consome ~128 MiB e demora cerca de 800 ms em hardware moderno.
O scrypt não está na Web Crypto API. Em JavaScript, use scrypt-js, @noble/hashes, ou libsodium.js. O Litecoin e o Dogecoin usam scrypt como prova de trabalho, o que incentivou o desenvolvimento de ASICs especificamente para scrypt, erodindo algo da sua vantagem assimétrica original contra ASICs.
Argon2id: o padrão de 2026
O Argon2 venceu a Password Hashing Competition em 2015. Três variantes: Argon2d (mais rápido, dependente de dados, vulnerável a canal lateral), Argon2i (independente de dados, mais lento), Argon2id (híbrido, recomendado para a maioria dos usos). O RFC 9106 padronizou-o em 2021.
Três parâmetros:
- t (tempo): iterações pela memória. Típico 2-3.
- m (memória): memória em KiB. Típico 65536 (64 MiB) ou superior.
- p (paralelismo): grau de paralelismo. Típico 1-4.
Linha de base OWASP 2024: t=2, m=19456 (19 MiB), p=1 para mínimo, e t=3, m=65536 (64 MiB), p=4 para protecção mais forte.
import { argon2id } from '@noble/hashes/argon2';
import { utf8ToBytes } from '@noble/hashes/utils';
const derivedKey = argon2id(utf8ToBytes(password), salt, {
t: 3, m: 65536, p: 4, dkLen: 32
});
Ou via argon2-browser (WASM):
import argon2 from 'argon2-browser';
const hash = await argon2.hash({
pass: password, salt,
type: argon2.ArgonType.Argon2id,
time: 3, mem: 65536, parallelism: 4, hashLen: 32
});
O Argon2id derrota os atacantes com GPU mais eficazmente do que o scrypt porque o seu padrão de acesso à memória é menos adaptável a designs de memória em massa. Os ASICs para Argon2 existem em investigação mas ainda não estão economicamente implementados à escala dos atacantes.
Escolha de parâmetros para a sua aplicação
O método de calibração: escolha o tempo de espera máximo que os seus utilizadores toleram (normalmente 500 ms a 2 segundos), meça no dispositivo alvo mais lento, e defina parâmetros para atingir esse orçamento.
Para partilhas de ficheiros protegidas por palavra-passe ao estilo HexaTransfer, onde a derivação acontece uma vez no envio e uma vez na transferência, 1-2 segundos é aceitável. Parâmetros:
- PBKDF2-SHA-256: 600.000-1.200.000 iterações
- scrypt: N=2^17, r=8, p=1
- Argon2id: t=3, m=65536, p=4
Para sistemas de autenticação onde o utilizador espera após introduzir a palavra-passe, 300-500 ms é o tecto de UX. Os parâmetros reduzem-se aproximadamente para metade. Para cenários em lote onde o utilizador não espera (por exemplo, re-encriptação em segundo plano), aumente para 3-5 segundos.
Gestão de salts
Todas as três KDFs precisam de um salt. Regras:
- 16 bytes aleatórios no mínimo
- Gerado via
crypto.getRandomValues(), nuncaMath.random() - Único por palavra-passe (se Alice e Bob usam a mesma palavra-passe, os salts devem diferir para que as chaves derivadas difiram)
- Não secreto — armazene-o junto ao texto cifrado
O pepper (um segredo adicionado a todas as derivações) é por vezes discutido. Para transferência de ficheiros onde o "servidor" é um simples armazém de blobs, o pepper não acrescenta valor pois não existe segredo do lado do servidor. Para sistemas baseados em conta, um pepper do lado do servidor armazenado separadamente da base de dados de palavras-passe torna os dumps de base de dados menos úteis para os atacantes.
Migração entre KDFs
Se tem um deployment existente em PBKDF2 e quer mudar para Argon2id:
- Armazene o identificador da KDF nos metadados do texto cifrado (
"kdf": "pbkdf2-sha256-600000"ou"kdf": "argon2id-3-65536-4") - Em novos envios, use Argon2id
- Na desencriptação, leia o identificador da KDF e use a função correspondente
- Nunca actualize cegamente textos cifrados antigos; precisaria da palavra-passe para re-derivar
O LastPass, 1Password e Bitwarden passaram todos por esta migração. Os três usam agora por defeito PBKDF2 com 600.000+ iterações, com Argon2id disponível em versões mais recentes. Mesmo os gestores de palavras-passe foram lentos a adoptar o Argon2 — está a ser implementado gradualmente porque o ecossistema de ferramentas demorou tempo a amadurecer.
E o bcrypt?
O bcrypt (1999) é uma boa função de hash de palavras-passe com resistência de memória modesta. Limita a entrada a 72 bytes (uma armadilha conhecida — palavras-passe longas são truncadas silenciosamente antes das rondas 2011). É o padrão histórico no Ruby on Rails e muitos frameworks PHP. Para código novo em 2026, prefira Argon2id; o bcrypt está adequado para manter sistemas existentes.
A recomendação realista
Para um novo serviço de transferência de ficheiros em 2026:
- Se puder incluir uma dependência de 15-200 KB: Argon2id via @noble/hashes ou libsodium.js
- Se precisar de zero dependências e tamanho de bundle mínimo: PBKDF2-SHA-256 com 600.000 iterações via Web Crypto
- Se estiver a criar uma carteira de criptomoedas ou algo que herda scrypt legado: scrypt com N=2^17
Para aplicações de produção que tratam ficheiros sensíveis, o Argon2id vale a dependência WASM. Para partilhas simples protegidas por palavra-passe onde os utilizadores geram uma palavra-passe aleatória de qualquer forma, o PBKDF2 é adequado porque a entropia está na palavra-passe, não na KDF.
Experimente em hexatransfer.com — gratuito, sem conta, até 10 GB.
Envie arquivos grandes com segurança e criptografia de ponta a ponta
Transfira arquivos de até 10 GB gratuitamente com criptografia de ponta a ponta. Sem necessidade de conta. Seus arquivos são criptografados no navegador antes do envio — ninguém mais pode lê-los.
Enviar um arquivo