Estágio 01 · 01-12
LockedA maioria dos devs trata crypto como caixa-preta: chama bcrypt, copia trecho de OAuth2, usa HTTPS, e nunca pensa de novo. Resultado: vulnerabilidades clássicas continuam aparecendo, senhas em SHA-256 sem salt, AES-CBC sem MAC vulnerável a padding oracle, JWT com alg:none, comparações de tokens com == em tempo não-constante, GCM com nonce reutilizado destruindo confidencialidade, certificate pinning ausente em mobile.
Você não precisa inventar primitives, isso é missão de criptógrafos. Mas precisa entender o que cada primitive garante, quando usar qual, quais são os modos de falha. Sem essa base, 02-13 (Auth, JWT/OAuth2/OIDC), 03-08 (OWASP), 04-11 (Web3) viram cargo cult e você vai escrever código inseguro com confiança.
Este módulo é o vocabulário e os princípios. Hash function, MAC, signature, symmetric vs asymmetric, AEAD, key derivation, key exchange, PKI, randomness. Plus os pitfalls clássicos.
Crypto sempre define o que assume sobre o atacante e o que garante:
Modelos: passive (sniffer), active (MitM, pode modificar), adaptive chosen-ciphertext (CCA2). Crypto moderno mira CCA2.
Função H : bytes* → bytes_n (saída fixa). Propriedades:
H(x), achar x é inviável.x, achar x' ≠ x com H(x') = H(x) é inviável.x ≠ x' com mesmo hash é inviável.Padrões atuais: SHA-256, SHA-3, BLAKE3. Aposentados/quebrados: MD5, SHA-1.
Hash não é pra senhas (rápido demais; vulnerável a brute force/GPU). Hash não é MAC (sem chave). Hash isolado em comunicação não previne MitM modificar tudo.
MAC(key, msg) → tag. Garantia: quem não tem key não consegue gerar tag válida. Provê integridade + autenticidade contra atacante ativo.
Construção principal: HMAC (RFC 2104), baseado em hash. HMAC-SHA256 é default seguro.
Verificação em tempo constante é obrigatória: comparar tag byte-a-byte e fazer early return em diff vaza tempo → atacante recupera tag bit-a-bit (timing attack). Use crypto.timingSafeEqual em Node, subtle.ConstantTimeCompare em Go, hmac.compare_digest em Python.
Sign(privkey, msg) → sig; Verify(pubkey, msg, sig) → bool. Diferente de MAC: chave de assinar é privada, chave de verificar é pública. Permite non-repudiation (só dono da privkey podia ter assinado).
Padrões:
Falhas clássicas: nonce reuse em ECDSA recupera privkey (Sony PS3, 2010). Use libs sérias.
Cifra de bloco: AES (128/192/256 bits). Opera em blocos de 128 bits.
Modos dizem como encadear blocos pra cifrar mensagem maior:
Nunca use AES isolado em bloco. Sempre use AEAD.
AEAD provê confidencialidade + integridade + autenticidade numa primitive:
Enc(key, nonce, plaintext, AD) → (ciphertext, tag)Dec(key, nonce, ciphertext, AD, tag) → plaintext or failPadrões: AES-GCM (hardware accelerated em x86), ChaCha20-Poly1305 (rápido em mobile/ARM, sem hardware AES).
Regras de ouro:
Pra "default seguro": libsodium (crypto_aead_xchacha20poly1305_ietf_encrypt), nonce de 192 bits que pode ser random sem medo de colisão.
Senhas e chaves vão por funções diferentes:
Para derivar chaves de uma master key: HKDF (HMAC-based Key Derivation Function, RFC 5869). Extract + Expand.
Senha em DB: nunca SHA-256. Sempre Argon2id (ou bcrypt se libs limitam). Sal aleatório por usuário, work factor que demora ~100ms numa máquina típica.
RSA (Rivest-Shamir-Adleman): segurança baseada em fatoração de inteiros grandes. Chaves de 2048+ bits hoje, 3072 recomendado. Lento.
ECC (Elliptic Curve Cryptography): segurança em discrete log em curvas. Chaves muito menores (256 bits ECC ≈ 3072 RSA). Curvas: P-256 (NIST), Curve25519 (Bernstein, mais segura por design).
Asymmetric é caro, você raramente cifra dados grandes com ele. Padrão: usar asymmetric pra estabelecer chave simétrica, então cifrar dados com simétrico (hybrid encryption).
DH permite que dois lados gerem shared secret sem nunca enviá-lo. Hoje, ECDH (DH em curva elíptica) é padrão.
Em TLS 1.3 e Signal, key exchange é ephemeral (DHE/ECDHE), gera chaves novas por sessão. Garante forward secrecy: se chave de longo prazo é comprometida no futuro, sessões antigas continuam seguras.
Como você sabe que a chave pública é mesmo do servidor? Resposta: certificate, assinada por CA (Certificate Authority) confiada.
Cadeia: certificate do servidor → assinada por intermediate CA → assinada por root CA (no trust store do OS/browser). Browser valida cadeia, validade, revocation, hostname (SAN).
Revocation: CRL (lista grande, raro funcionando), OCSP (online check, privacy issue), OCSP stapling (servidor entrega resposta OCSP pré-assinada). Em mobile, certificate pinning é mais robusto.
ACME (Let's Encrypt): automation de emissão.
TLS 1.3 (RFC 8446) drasticamente simplificou:
ClientHello → ServerHello (com key share) → cifrar resto. Authenticate via certificate + signature.
PRNG (Math.random, rand() em C): NÃO use em crypto. Previsível.
CSPRNG (Cryptographically Secure):
/dev/urandom, syscall getrandom.crypto.randomBytes, crypto.randomUUID.crypto.getRandomValues.Entropia inicial vem de timing de hardware events; depois CSPRNG expande deterministicamente. Em containers/VMs, garantir entropia inicial é cuidado real (haveged, virtio-rng).
Nunca use timestamp como token. Nunca use sequencial.
alg:none: aceita token sem verificar assinatura. Lib mal-feita aceita.alg confusion: trocar RS256 por HS256 e usar pubkey como "secret".Algoritmos viram ruins (MD5, SHA-1, RC4). Sistema deve ser capaz de trocar sem rewrite, versionar formato (v1$argon2id$..., v2$...), suportar múltiplos algorithms em paralelo, ter rotation plan de chaves.
Computadores quânticos teóricos quebram RSA, DH, ECC via algoritmo de Shor. Hash e simétrico (AES) sobrevivem com chaves maiores (Grover dá speedup quadrático em busca, não exponencial).
Estado atual (2025-2026): NIST finalizou primeiro batch pós-quântico em agosto 2024:
| Standard | Algoritmo base | Uso | Status |
|---|---|---|---|
| FIPS 203 | ML-KEM (ex-Kyber) | KEM (key encapsulation) | Recomendado pra TLS, key exchange |
| FIPS 204 | ML-DSA (ex-Dilithium) | Assinatura | Recomendado pra signatures gerais |
| FIPS 205 | SLH-DSA (ex-SPHINCS+) | Assinatura hash-based | Backup conservador (sem assumptions de lattice) |
| (em finalização) | ML-DSA-44/Falcon | Assinatura compacta | Pra firmware, certificates |
Por que importa hoje (não em 10 anos):
O que está acontecendo na prática:
sntrup761x25519-sha512 hybrid em key exchange.Trade-offs práticos:
Quando você toca:
Não implemente PQ crypto você mesmo, use liboqs (Open Quantum Safe), AWS-LC, OpenSSL 3.5+, ou BoringSSL. Cripto pós-quântica é especialmente sensível a side-channels novos (timing em lattice ops).
Crypto correto exige código sem branches dependentes de segredo e sem memory access dependente de segredo:
if secret_byte == X → branch predictor leak.lookup_table[secret_byte] → cache timing leak.Implementações sérias usam mascaramento, instruções constant-time, hardware AES (AES-NI). Nunca implemente AES em JS você mesmo.
Você precisa, sem consultar:
alg:none attack de alg confusion em JWT.crypto.timingSafeEqual resolve.Construir uma biblioteca mínima de utilitários crypto seguros em TypeScript usando crypto nativo do Node, e uma suite de demos de ataques que falham na versão errada e passam na correta.
safe_crypto:
hashPassword(password) / verifyPassword(password, hash), Argon2id via argon2 package.aeadEncrypt(key, plaintext, ad) / aeadDecrypt(key, ciphertext, ad), XChaCha20-Poly1305 (libsodium via sodium-native), nonce random embutido.signHmac(key, msg) / verifyHmac(key, msg, tag), HMAC-SHA256 com timingSafeEqual.signEd25519(privkey, msg) / verifyEd25519(pubkey, msg, sig).deriveKey(masterKey, info, len), HKDF.randomToken(bytes), CSPRNG.=== vs timingSafeEqual.hashcat-style em set de 100 senhas comuns; mostre ratio de cracking.alg:none em parser ingênuo vs jose lib.THREAT-MODEL.md:
v1$argon2id$...) e rotação automática em login bem-sucedido.opensk ou implemente WebAuthn relying party básico em Node.