Codigos Secretos Para Conversar
Como criar sistemas de mensagens secretas entre processos
A maioria dos desenvolvedores não para para pensar em como seus serviços se comunicam de verdade. Você tem um backend rodando em Node, um worker em Python e um serviço em Go que precisa trocar dados sem exporPayloads sensíveis na rede. É aí que entram os códigos secretos para conversar. Não estou falando de cifra de César ou nada que se aprende em site de fã de espiões. Estou falando de mecanismos práticos de codificação e troca de chaves que permitem que dois processos falem algo que um terceiro processo não consegue decifrar sozinho. O problema é que a maioria dos tutoriais na internet fala como fazer isso em teoria e esquece de mencionar o que quebra na prática.
Entendendo a base dos codigos secretos para conversar
O conceito central é simples: dois processos compartilham uma chave secreta e usam um algoritmo de criptografia simétrica para cifrar e decifrar mensagens. O padrão que funciona na maioria dos cenários reais é AES-256-GCM. Ele oferece confidencialidade e integridade ao mesmo tempo, o que significa que você não precisa montar uma solução separada para verificar se a mensagem foi alterada no trânsito. A primeira coisa que todo mundo erra é a geração da chave. Você não pode usar uma string fixa como senha. Já vi gente usando "meusistema123" como chave AES e se perguntando por que os logs de segurança acionavam alertas. A chave precisa ter 32 bytes gerados aleatoriamente. Em JavaScript você usa crypto.randomBytes(32), em Python usesecrets.token_bytes(32), em Go you usecrypto/rand.Read(). O princípio é o mesmo: entropia real, não criatividade. Outro erro comum é reutilizar o IV (vetor de inicialização). O IV não é segredo, mas cada mensagem deve ter um IV diferente. Se você reutilizar o IV com a mesma chave, padrões na mensagem podem vazar. Em GCM, o IV típico tem 12 bytes. Gere um novo a cada operação de criptografia e anexe-o à mensagem cifrada, geralmente na frente dos bytes cifrados.
O método prático
Vou descrever o fluxo que eu uso e que já passou por produção em três sistemas diferentes. Não é perfeito, mas funciona e é previsível o suficiente para manter sob controle. O primeiro passo é estabelecer a chave compartilhada. Se os dois processos estão no mesmo servidor, você pode gerar a chave em um processo e escrevê-la em um arquivo com permissões restritas, ou passar via variável de ambiente. Se estão em máquinas diferentes, aí entra a troca de chaves. O padrão mais comum é usar um handshake inicial via Diffie-Hellman para derivar a chave simétrica. Se isso parece complexo demais, pelo menos use TLS no transporte. Não reinvente a roda só para impressionar. Para cifrar uma mensagem, o procedimento é: gerar IV, criptografar com AES-GCM usando a chave e o IV, concatenar IV + ciphertext, e opcionalmente adicionar um timestamp para evitar replay attacks. O timestamp é simples — inclui os segundos desde epoch dentro do plaintext ou como additional authenticated data no GCM. Se uma mensagem com timestamp antigo chegar, descarta.

Para decifrar, o procedimento inverso: separar os primeiros 12 bytes como IV, o resto como ciphertext, chamar a função de decifração do AES-GCM e verificar se o timestamp é aceitável. Aqui vai um exemplo concreto em Node.js:
const crypto = require('crypto');
const ALGO = 'aes-256-gcm';
const KEY = crypto.randomBytes(32); // faça isso uma vez, armazene com segurança
function encrypt(plaintext) {
const iv = crypto.randomBytes(12);
const cipher = crypto.createCipheriv(ALGO, KEY, iv);
let encrypted = cipher.update(plaintext, 'utf8', 'base64');
encrypted += cipher.final('base64');
const authTag = cipher.getAuthTag().toString('base64');
return Buffer.from(iv + authTag + encrypted, 'binary').toString('base64');
}
function decrypt(encryptedBase64) {
const data = Buffer.from(encryptedBase64, 'base64');
const iv = data.slice(0, 12);
const authTag = data.slice(12, 28);
const encrypted = data.slice(28).toString();
const decipher = crypto.createDecipheriv(ALGO, KEY, iv);
decipher.setAuthTag(authTag);
let decrypted = decipher.update(encrypted, 'base64', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
Esse código é funcional mas incompleto para produção — falta verificação de timestamp e tratamento de erro na decifração. O erro que mais aparece é "invalid signature" no GCM, que acontece quando um único bit da mensagem foi corrompido ou quando alguém tentou decifrar com a chave errada. Trate isso explicitamente e não mostre o erro completo para o usuário final, só logue internamente. O maior problema que eu tive com esse tipo de sistema aconteceu num cenário onde precisávamos comunicar um serviço em Node com um serviço legado em Java rodando numa máquina virtual antiga. A bibliotecaaes util do Java 8 tem um comportamento diferente do Node em relação ao padding. O Node com GCM não usa padding, mas se por acaso alguém configure Cipher.getInstance("AES/GCM/NoPadding") no Java de forma inadequada, a mensagem simplesmente não decifra e não há nenhum aviso útil no log. A solução foi verificar o tamanho exato do ciphertext antes de enviar. Com GCM, o tamanho da mensagem cifrada é o tamanho do plaintext mais 16 bytes de tag. Se o Java estava recebendo um tamanho diferente, sabíamos que havia um problema de configuração no lado dele. Também forcamos ambos os lados a usarem a mesma representação de bytes e paramos de confiar em conversões implícitas de encoding.
Outro problema recorrente é a perda da chave em produção. Já vi equipe inteira perder horas porque o container que tinha a chave foi recriado sem persistência. A solução é tratar a chave como infraestrutura — storage gerenciado com rotação controlada, nunca hardcode, nunca no código-fonte. Use AWS Secrets Manager, HashiCorp Vault ou algo similar. Se não tiver orçamento para isso, no mínimocriptografe a chave com uma chave mestra e armazene o resultado em ambiente seguro.

O que esse método não faz bem
Essa abordagem de criptografia simétrica com chave compartilhada funciona bem quando você controla ambos os lados da comunicação e pode distribuir a chave de forma segura. Não funciona bem quando você precisa de autenticação de identidade forte entre partes desconhecidas. Nesse caso, assinaturas digitais com chaves assimétricas são mais adequadas. Também não protege contra ataques de replay se você esquecer de incluir timestamp ou nonce único. E não é eficiente para mensagens extremamente pequenas — a sobrecarga de IV mais auth tag consome cerca de 28 bytes, o que é significativo se você está enviando payloads de 10 bytes. Se o seu cenário envolve apenas comunicação interna em mesma rede, considere usar TLS diretamente. É mais simples, amplamente testado e você não precisa gerenciar chaves manualmente. A complexidade que esse método adiciona só justifica o esforço quando TLS não é suficiente ou viável.
Dica técnica que ninguém conta
Uma coisa que acelera bastante o debug é logar apenas o comprimento dos pacotes cifrados e o timestamp de envio e recebimento, sem logar o conteúdo. Isso ajuda a detectar padrões de tráfego anormais sem expor os dados que você tentou proteger. Também ajuda a identificar rapidamente se um serviço está retransmitindo mensagens ou se há latência anormal na criptografia/decifração. Se precisar testar localmente, crie um par de chaves de teste separado das chaves de produção. Nunca use as mesmas chaves nos dois ambientes. Já vi gente rodar testes com as chaves de produção e sujar o keyring inteiro, obrigando a rotação de emergência em horário comercial. O campo de criptografia aplicada tem muitos atalhos que parecem boas ideias até darem problema. O básico bem feito — chave gerada corretamente, IV único por mensagem, verificação de integridade, timestamp anti-replay — cobre a maior parte dos casos. O resto é ajuste fino conforme o cenário exige.
Galeria
-
50 CÓDIGOS SECRETOS EN CHATGPT (La guía más simplificada de prompting ... -
Códigos secretos en Android y iPhone: cuales existen, el listado ... -
Tarjetas Codigos Secretos | PDF