Criptografia
Senhas e hash com Argon2id
Por que hashes rápidos falham em senhas, o que fazem o salt e o fator de trabalho, e como gerar e verificar hashes com Argon2id em Python.
Separe codificação, criptografia e hash com laboratórios de Base64, SHA-256 e OpenSSL. Entenda por que Base64 não protege e o hash é de mão única.
Codificação, criptografia e hash transformam dados em outra coisa, e por isso as pessoas misturam os três. Eles têm objetivos diferentes. A codificação muda a forma como os dados são escritos, então qualquer pessoa consegue desfazê-la. A criptografia esconde os dados de quem não tem uma chave, e você desfaz o processo com essa chave. O hash gera uma impressão digital curta que não volta ao conteúdo original. Se você guardar só uma frase: Base64 não é criptografia, e um hash não esconde nada de entradas curtas.
Este artigo separa as três ideias e pede que você execute cada uma no terminal com o mesmo texto. Assim você compara os resultados com os seus próprios olhos.
Você precisa de um terminal com base64, sha256sum e openssl. No Windows 11, os comandos abaixo rodam no Git Bash, que vem com o Git para Windows. Há também uma versão em PowerShell para o passo do hash. Você não precisa saber criptografia antes, mas ler o artigo sobre a cifra de César ajuda a entender a ideia de chave.
Todos os comandos do laboratório são seguros para rodar na sua máquina. Use um arquivo de teste, não um segredo de verdade.
As três operações respondem a três perguntas diferentes.
| Operação | Pergunta que responde | Precisa de chave? | Pode ser desfeita? |
|---|---|---|---|
| Codificação | Como represento estes bytes como texto ou num formato que outro sistema espera? | Não | Sim, por qualquer pessoa |
| Criptografia | Quem pode ler estes dados? | Sim | Sim, por quem tem a chave certa |
| Hash | Estes dados mudaram, ou dois valores são iguais? | Não | Não, por projeto |
Tenha esta tabela em mente durante o laboratório. O resto do artigo explica cada linha.
Codificação reescreve os dados em outra forma para que um sistema consiga transportá-los. O Base64 é o exemplo clássico. Ele pega bytes e os escreve com 64 caracteres imprimíveis: A a Z, a a z, 0 a 9, + e /, com = usado como preenchimento. A RFC 4648 define o formato. Anexos de e-mail, data URLs e muitos payloads de API usam Base64 porque o canal espera texto.
O Base64 não tem segredo. A tabela de conversão é pública e fixa. Qualquer ferramenta que conheça a regra consegue transformar a saída de volta na entrada. Esse é o propósito da codificação: interoperabilidade, não sigilo.
Criptografia pega dados legíveis, chamados de texto claro, e os transforma com um algoritmo e uma chave em texto cifrado. Quem não tem a chave não deveria aprender nada útil com o texto cifrado. Quem tem a chave consegue decifrar.
Existem duas famílias. A criptografia simétrica usa a mesma chave secreta para cifrar e decifrar. O AES é a escolha mais comum. A criptografia assimétrica usa uma chave pública e uma chave privada. Este artigo usa criptografia simétrica, porque o comando do OpenSSL no laboratório também usa.
Criptografia boa depende de mais do que o algoritmo. Você precisa escolher um modo seguro, gerar chaves com uma fonte aleatória confiável e proteger a chave. O comando do OpenSSL no laboratório usa uma senha e PBKDF2 para derivar a chave. O texto de ajuda do OpenSSL diz que o PBKDF2 usa 10.000 iterações por padrão, a não ser que você troque esse valor com -iter.
Uma função de hash criptográfico recebe uma entrada de qualquer tamanho e devolve uma saída de tamanho fixo. O SHA-256 está especificado na FIPS 180-4, e a saída dele tem sempre 256 bits, escritos como 64 caracteres hexadecimais. Duas propriedades importam para quem está começando:
O hash é de mão única. Nada na saída mostra o texto original. Você consegue verificar se uma entrada candidata produz um hash conhecido. Não consegue recuperar a entrada só a partir do hash, a não ser adivinhando e testando.
Lembre que um hash é uma impressão digital, não uma fechadura. Qualquer pessoa pode calcular o SHA-256 de um arquivo público. O hash prova que duas cópias são iguais. Ele não esconde o arquivo.
A maior parte dos erros reais de segurança nessa área vem de usar a ferramenta errada para o trabalho.
Entender essa diferença cedo evita essas armadilhas.
Abra o Git Bash numa pasta vazia. Codifique uma frase curta e depois decodifique o resultado.
echo -n 'hello lab' | base64A saída que obtive nesta máquina, com OpenSSL 3.2.4 e Git Bash:
aGVsbG8gbGFiAgora decodifique essa saída:
echo -n 'aGVsbG8gbGFi' | base64 -dSaída:
hello labDuas coisas para notar. Primeiro, nenhuma chave entrou na história. Segundo, o echo -n importa. Sem o -n, o echo acrescenta uma quebra de linha, e a saída em Base64 muda. Rode echo 'hello lab' | base64 e compare: obtive aGVsbG8gbGFiCg==. Aqui, o Base64 transforma 9 bytes em 12 caracteres, então a saída fica mais longa que a entrada.
Pergunte a si mesmo: alguém sem nenhum segredo conseguiria desfazer isso? Consegue. É esse teste que separa codificação de criptografia.
Passe a mesma frase pelo SHA-256:
echo -n 'hello lab' | sha256sumSaída:
8fc6baba79a0d60b37dee612ccc1ec096ef52dba8cb0a24a6451e8bfb0e4d761 *-Agora acrescente um ponto de exclamação e rode de novo:
echo -n 'hello lab!' | sha256sumSaída:
36902fb7fdea33458ad09dfeb52118dc47f99a8ca2b9001080366d55511de915 *-Os dois hashes não têm nenhum padrão visível em comum. Um único caractere mudou a saída inteira. Os dois têm 64 caracteres hexadecimais, ou seja, 256 bits.
O - no fim indica que a entrada veio da entrada padrão, não de um arquivo. O * antes dele é a marca de modo binário que o sha256sum do Git Bash imprime. Outros sistemas podem imprimir dois espaços, e o hash é o mesmo. O hash de um arquivo funciona do mesmo jeito.
Crie um arquivo pequeno e calcule o hash:
echo 'secret note' > note.txt
sha256sum note.txtNa minha máquina, com quebras de linha no formato Unix no arquivo, a saída foi:
b5f891a5e064fec661025d0b0ec2de157487a6c2e5cc46dc0971fee56f86c645 *note.txtMude o arquivo, mesmo que seja um único caractere, e calcule o hash de novo. O valor vai ser outro. É assim que as verificações de integridade funcionam. A verificação diz que o arquivo mudou. Não diz o que mudou, e não impede um atacante de alterar o arquivo e o hash publicado ao mesmo tempo.
Se preferir o PowerShell, o Windows tem um comando embutido:
Get-FileHash note.txt -Algorithm SHA256Confira na saída a linha Hash, que mostra 64 caracteres hexadecimais. O hash depende dos bytes exatos do arquivo. O Set-Content do PowerShell grava quebras de linha do Windows (CRLF), que são diferentes do LF do exemplo em Bash acima. Na minha máquina, um arquivo gravado dessa forma gerou este hash:
406A5646AE75CA75D032F306ABD33085DC9F656E3109BB962AEAB335EEC9ED85Os mesmos bytes calculados com sha256sum no Git Bash deram o mesmo valor, em minúsculas. Se o seu hash for diferente do exemplo em Bash, mas bater com o resultado do PowerShell para o seu próprio arquivo, a causa são as quebras de linha.
Crie uma nota e criptografe com AES-256-CBC. O OpenSSL vai pedir uma senha. Escolha uma que você lembre e use só neste laboratório.
echo 'secret note' > note.txt
openssl enc -aes-256-cbc -pbkdf2 -salt -in note.txt -out note.encO OpenSSL pede a senha, e o arquivo criptografado é gravado em note.enc. A opção -salt acrescenta um sal aleatório, então criptografar o mesmo arquivo duas vezes gera saídas diferentes. Um arquivo criptografado com -salt começa com o texto ASCII Salted__. Confirmei isso na minha máquina. O resto do arquivo é binário e ilegível.
Agora descriptografe:
openssl enc -d -aes-256-cbc -pbkdf2 -in note.encDigite a mesma senha. Saída:
secret noteA descriptografia só funciona com a senha certa. Testei com uma senha errada. O OpenSSL mostrou bad decrypt e saiu com erro.
Em seguida, altere um byte do arquivo criptografado e tente descriptografar. Inverti um bit dentro do bloco cifrado de uma cópia chamada tampered.enc. A descriptografia falhou com bad decrypt, e o comando saiu com status 1.
Essa falha é um acidente de sorte do preenchimento do modo CBC. Outras mudanças podem gerar lixo sem nenhum erro. A lição é que a criptografia simples não dá um sinal confiável de que o texto cifrado foi modificado. Sistemas que precisam de sigilo e integridade ao mesmo tempo usam criptografia autenticada, como o AES-GCM, ou acrescentam um código de autenticação de mensagem. É um tema avançado, mas explica por que um arquivo criptografado não é automaticamente um arquivo confiável.
Passe o mesmo texto por cada operação e compare:
| Operação | Comando | Saída para hello lab (observada) |
|---|---|---|
| Codificação | echo -n 'hello lab' | base64 |
aGVsbG8gbGFi |
| Hash | echo -n 'hello lab' | sha256sum |
8fc6baba...e4d761 |
| Criptografia | openssl enc ... -in note.txt |
Dados binários, precisa da senha para ler |
Pergunte o que cada saída permite fazer:
hello lab.hello lab, mas não recuperar a entrada só a partir do hash.secret note apenas com a senha.Chamar Base64 de "criptografia" ou "ofuscação" para segredos. O Base64 não esconde nada. Quem vê uma string em Base64 consegue decodificá-la. Guarde segredos num gerenciador de segredos ou num armazenamento criptografado, não em forma codificada.
Usar hash como fechadura. O hash é de mão única, mas entradas curtas ou comuns podem ser adivinhadas. Calcule o hash de hello lab e um atacante com uma lista de frases comuns recupera o texto sem quebrar o SHA-256. Por isso o hash de senhas precisa de sal e de algoritmos lentos.
Usar SHA-256 puro para senhas. O SHA-256 é rápido por projeto, o que serve para somas de verificação de arquivos e não serve para guardar senhas. Use uma função de hash de senha feita para isso.
Confiar num hash que vem do mesmo lugar que o arquivo. Um checksum na mesma página comprometida não prova nada. Obtenha o hash esperado por um canal separado e confiável, ou verifique uma assinatura digital.
Esquecer que a criptografia exige gestão de chaves. O laboratório usa uma senha digitada no prompt. Sistemas reais precisam guardar, trocar e proteger chaves. Perder a chave significa perder os dados.
Escrever sua própria criptografia. Use bibliotecas e protocolos estabelecidos. Os comandos do laboratório servem para aprender, não são modelo para sistemas de produção.
Repita os três laboratórios com outra frase e depois com um arquivo de alguns kilobytes. Veja que a saída em Base64 cresce cerca de um terço, que o hash continua com 64 caracteres e que o arquivo criptografado cresce só pelo cabeçalho e pelo preenchimento.
Depois, leia sobre hash de senhas. O problema ali não é o hash em si, e sim o custo de adivinhar. O próximo artigo da série, Como funciona o hash de senhas com Argon2id, explica sal, fator de trabalho e por que hashes lentos importam. Se quiser revisar o lado das cifras antes, leia Cifra de César em Python. Ele mostra uma chave e um algoritmo numa forma que você consegue testar.
Ao estudar protocolos reais, observe três coisas em cada projeto: o que ele codifica, o que ele criptografa e o que ele calcula como hash. A maior parte da confusão some quando você pergunta qual dos três trabalhos cada parte está fazendo.
Criptografia
Por que hashes rápidos falham em senhas, o que fazem o salt e o fator de trabalho, e como gerar e verificar hashes com Argon2id em Python.
Criptografia
Chaves pública e privada do zero: o que uma assinatura prova, por que a chave privada fica em segredo e um lab Ed25519 em que um arquivo alterado falha.
Criptografia
Criptografia do zero: cifragem, chaves, hashes, assinaturas e por que a cifra de César ensina ideias, mas não protege nada.