Segurança

Hashing, criptografia e encoding: as diferenças

Base64, SHA-256 e AES fazem coisas que, à primeira vista, parecem a mesma: entra um texto legível, sai um monte de caracteres embaralhados. É daí que nascem bugs de segurança sérios, gente "criptografando" senha com Base64, guardando senha em MD5, ou tratando um hash como se desse para reverter. A diferença cabe em duas perguntas: dá para voltar ao original? E, se dá, precisa de uma chave? Encoding volta sem segredo nenhum (não é segurança); criptografia volta só com a chave certa; hash não volta de jeito nenhum, por projeto. Este guia separa os três, mostra por que o hash de uma senha não é como o hash de um arquivo, e por que o SHA-256, que é excelente para arquivo, é péssimo para senha justamente por ser rápido demais.

J-Kit16 min de leituraIntermediário
  • Hashing
  • Criptografia
  • Encoding
  • Segurança

Resumo rápido

  • Encoding (Base64, hex) é reversível e sem segredo: serve para transporte e representação, nunca para proteger.
  • Hashing é irreversível por projeto: não existe des-hashear. Serve para integridade e, com sal e função lenta, para senhas.
  • Criptografia é reversível com chave: serve para confidencialidade. Senha nunca se criptografa.
  • SHA-256 é rápido demais para senha (bilhões de tentativas por segundo em GPU), daí bcrypt, scrypt e Argon2.

Três operações, um mal-entendido

As três técnicas embaralham texto, mas resolvem problemas diferentes. Encoding quer caber num canal e ser lido de novo; hashing quer uma impressão digital que prove que nada mudou; criptografia quer esconder o conteúdo de quem não tem a chave. Em vez de decorar exemplos, guarde os dois eixos que separam tudo: a reversibilidade e a presença de uma chave. Encoding é reversível sem chave; criptografia é reversível com chave; hashing não é reversível de forma alguma.

Encoding

  • Reversível? Sim, por qualquer um.
  • Precisa de chave? Não.
  • Serve para: transportar e representar bytes (Base64, hex, URL).

Criptografia

  • Reversível? Sim, com a chave certa.
  • Precisa de chave? Sim, esse é o ponto.
  • Serve para: confidencialidade (AES, RSA).

Hashing

  • Reversível? Não, por projeto.
  • Precisa de chave? Não (só o HMAC usa uma).
  • Serve para: integridade, impressão digital, senhas com sal.

O teste mais rápido é passar o mesmo texto pelas três operações e ver o que dá para desfazer em cada caso. Abaixo, a palavra senha123 vira três saídas bem diferentes, e só uma delas depende de um segredo para voltar ao original.

Entrada / Input:  senha123

Base64   ->  c2VuaGExMjM=
             reverte sem segredo: qualquer um lê "senha123" de volta
             reverses with no secret: anyone reads "senha123" back

SHA-256  ->  55a5e9e78207b4df8699d60886fa070079463547b095d1a05bc719bb4e6cd251
             irreversível: só dá para adivinhar a entrada e recalcular
             irreversible: you can only guess the input and recompute

AES-GCM  ->  (bundle base64, muda a cada execução)
             reverte apenas com a senha correta
             reverses only with the correct passphrase
A mesma entrada por três caminhos. Base64 volta sozinho, o hash não volta, e o AES só volta com a chave. Confira você mesmo no [gerador de hash](tool:gerador-hash) e no [codificador de texto](tool:codificador-texto).

Encoding: representar, não proteger

Encoding traduz dados de um formato para outro por uma regra pública e reversível. O objetivo é caber em um canal. Base64, definido na RFC 4648, agrupa três bytes (24 bits) em quatro caracteres de 6 bits tirados de um alfabeto de 64 símbolos, para mandar binário por e-mail ou em JSON sem quebrar nada. O hexadecimal mostra cada byte como dois dígitos legíveis. O URL-encoding escapa caracteres especiais dentro de um link. Não há chave nem segredo em nenhum deles: quem tem o valor codificado sempre recupera o original.

"oi"  ->  Base64     ->  "b2k="      (qualquer um reverte / anyone reverses)
"oi"  ->  hex        ->  "6f69"
"a b" ->  URL-encode ->  "a%20b"

// Base64url (RFC 4648 §5): variante URL-safe, troca + por - e / por _,
// e descarta o padding "=". É a codificação de tokens, JWT e chaves em URL.
Encoding é público e reversível. O base64url é a variante que cabe em URLs e cabeçalhos, a mesma usada nas partes de um [JWT](guide:jwt-anatomia-assinatura-seguranca).

Hashing: a impressão digital irreversível

Uma função de hash transforma qualquer entrada em uma saída de tamanho fixo. É determinística (a mesma entrada dá sempre a mesma saída), sensível (mudar um bit muda o resultado inteiro, o efeito avalanche) e, quando criptográfica, inviável de reverter. As famílias SHA-1 e SHA-2 (SHA-256, SHA-384, SHA-512) estão na norma FIPS 180-4 do NIST; a família SHA-3, baseada no Keccak, está na FIPS 202, aprovada em 5 de agosto de 2015. Não existe descriptografar um hash: a verificação é recalcular o hash e comparar. Um checksum como o CRC32 não é hash criptográfico, detecta erro acidental, não adulteração; é da mesma família do dígito verificador do CPF e do CNPJ.

A força de um hash criptográfico se mede por três resistências. Elas não caem juntas: uma função pode ainda resistir à pré-imagem e já ter perdido a resistência à colisão, foi exatamente o que aconteceu com o SHA-1.

Resistência à pré-imagem
Dado um hash h, é inviável achar qualquer entrada m com hash(m) = h. É o que impede reverter o digest de um arquivo ou de uma senha.
Resistência à segunda pré-imagem
Dada uma entrada m1, é inviável achar uma m2 diferente com o mesmo hash. Protege um documento específico contra ser substituído por outro com o mesmo digest.
Resistência à colisão
É inviável achar qualquer par m1 diferente de m2 com o mesmo hash. É a mais fácil de quebrar (limite do aniversário) e foi a primeira a cair no MD5 e no SHA-1.

Por que a colisão é a mais fácil? Pelo paradoxo do aniversário. Achar uma entrada que bate com um hash fixo custa cerca de 2^n tentativas (n é o tamanho do hash em bits). Mas achar duas entradas quaisquer que colidam entre si custa só cerca de 2^(n/2), porque cada nova entrada pode colidir com todas as anteriores. É a mesma razão pela qual, numa sala de 23 pessoas, a chance de duas fazerem aniversário no mesmo dia já passa de 50%.

colisao_esperada ~= 2^(n/2) SHA-256 -> 2^128 MD5 -> 2^64
n
tamanho da saída do hash, em bits (SHA-256 = 256, MD5 = 128)
2^(n/2)
número de entradas testadas antes de esperar duas com o mesmo hash
Esforço para achar uma colisão em um hash de n bits, no caso ideal (sem falha no algoritmo).
2^128colisão ideal no SHA-256 (~3,4 × 10^38 tentativas)
2^64colisão ideal no MD5 (~1,8 × 10^19 tentativas)
2^24colisão REAL no MD5 hoje: segundos num laptop

Primeiro exemplo trabalhado, em números: dobrar o hash de 128 para 256 bits eleva o esforço ideal de colisão de 2^64 para 2^128, um fator de 2^64, quase 18,5 quintilhões de vezes mais trabalho. É por isso que 256 bits não é "o dobro" de 128: é exponencialmente mais. Mas repare na terceira coluna: no MD5, o número ideal de 2^64 é ficção. A criptanálise de 2004 derrubou o custo real para a casa de 2^24, colisões de MD5 saem em segundos num notebook. Um hash "de 128 bits" com o algoritmo quebrado não vale 2^64; vale quase nada. Tamanho de saída só protege enquanto o algoritmo por dentro continua íntegro. Gere e compare digests no gerador de hash abaixo e reconheça um digest pelo formato com o identificador de hash.

O gerador cobre MD5, SHA-1, a família SHA-2, checksums (CRC32, Adler-32, FNV-1a) e HMAC, tudo no navegador. Digite um texto e veja o efeito avalanche mudando um caractere.Abrir a ferramenta em página inteira

Quando um hash quebra: MD5 e SHA-1

Quebrar um hash quase nunca significa reverter a saída, significa achar uma colisão que não deveria existir com tão pouco esforço. No MD5, colisões para a função completa foram anunciadas por Wang, Feng, Lai e Yu em agosto de 2004. No SHA-1, o golpe veio em duas ondas. Em fevereiro de 2017, o ataque SHAttered da CWI e do Google produziu dois PDFs diferentes com o mesmo hash SHA-1, gastando cerca de 2^63,1 operações, bem abaixo dos 2^80 que a teoria previa. Em janeiro de 2020, Leurent e Peyrin publicaram o SHA-1 is a Shambles, uma colisão de prefixo escolhido: o atacante fixa dois começos arbitrários e diferentes e ainda assim faz os hashes baterem. É o tipo de colisão que forja certificado e assinatura, e custou cerca de US$ 45 mil em GPU alugada, barato para um atacante determinado.

Um detalhe honesto: nem toda resistência do SHA-1 caiu. A resistência à colisão foi quebrada; a resistência à pré-imagem (achar uma entrada para um hash dado) segue sem ataque prático. Mesmo assim, um hash que perdeu a resistência à colisão não serve para assinatura nem certificado, e é por isso que navegadores e autoridades certificadoras aposentaram o SHA-1. Para escolher o que usar hoje, a tabela abaixo resume o estado de cada família.

Referência rápida. O [gerador de hash](tool:gerador-hash) cobre MD5, SHA-1, SHA-2, checksums e HMAC; SHA-3 e as funções de senha (bcrypt, scrypt, Argon2) são categorias à parte, não incluídas nele.
AlgoritmoSaídaStatus
MD5128 bitsNão usar, colisões práticas desde 2004.
SHA-1160 bitsNão usar, colisão prática (2017) e de prefixo escolhido (2020).
SHA-256 / SHA-512256 / 512 bitsUsar, padrão atual para integridade (FIPS 180-4).
SHA-3 (Keccak)224–512 bitsUsar, construção esponja, imune a length extension (FIPS 202).
CRC32 / Adler-3232 bitsSó erro acidental, não é criptográfico, não resiste a adulteração.
HMAC-SHA-256256 bitsUsar, integridade e autenticidade com chave secreta.
bcrypt / scrypt / Argon2variávelUsar, só para SENHAS: lentas e ajustáveis de propósito.
  1. 1992MD5 (RFC 1321)

    Ronald Rivest publica o MD5, digest de 128 bits que domina a década.

  2. 1995SHA-1 (FIPS 180-1)

    O NIST publica o SHA-1, de 160 bits, como sucessor mais robusto.

  3. 2004Colisões no MD5

    Wang et al. anunciam colisões para o MD5 completo na CRYPTO 2004.

  4. 2015SHA-3 padronizado (FIPS 202)

    O NIST aprova a família Keccak/SHA-3 em 5 de agosto; construção esponja.

  5. 2015Argon2 vence o PHC

    A Password Hashing Competition elege o Argon2 como função de senha de referência (julho).

  6. 2017SHAttered

    CWI e Google produzem a primeira colisão prática do SHA-1 (23 de fevereiro).

  7. 2020SHA-1 is a Shambles

    Leurent e Peyrin demonstram colisão de prefixo escolhido por ~US$ 45 mil.

  8. 2021RFC 9106

    A IETF padroniza o Argon2 para hashing de senha e proof-of-work (setembro).

Criptografia: reversível com chave

Criptografia embaralha o conteúdo de forma que só quem tem a chave o recupera. Na simétrica, a mesma chave cifra e decifra, é rápida e ideal para volume de dados; o AES é o exemplo. Na assimétrica, um par de chaves pública/privada permite que qualquer um cifre para você, mas só você decifre (RSA, curvas elípticas), o que resolve troca de chave e assinatura digital, a base do HTTPS. Um cuidado essencial: cifrar não é só esconder, é esconder de forma autenticada. O AES-GCM é um AEAD (criptografia autenticada) e, além do sigilo, produz uma etiqueta que detecta qualquer adulteração. E jamais use o modo ECB, que vaza a estrutura do texto, o caso do pinguim, no fim desta seção, mostra por quê.

AEAD (AES-GCM)
Criptografia autenticada: além de cifrar, gera uma etiqueta de integridade. A criptografia de texto usa AES-GCM de 256 bits com a chave derivada da sua senha por PBKDF2-HMAC-SHA-256.
Assimétrica (RSA / ECDH)
Par pública/privada. ECDH acerta uma chave sem trocá-la em claro; RSA e ECDSA assinam. Nenhum segredo precisa ser compartilhado antes.
HMAC (RFC 2104)
Hash com chave que prova integridade E autoria de uma mensagem. Imune a length extension por construção, por isso substitui hash(chave ‖ mensagem).

A criptografia de texto do site é um bom lugar para ver a diferença na prática: você digita uma senha, ela deriva a chave por PBKDF2 e cifra com AES-GCM; sem a senha, o texto cifrado é ruído. Se um sistema consegue mostrar o valor original de volta sem você digitar chave nenhuma, então aquilo não era criptografia, era encoding disfarçado. Um JWT ilustra a armadilha oposta: ele é assinado, não cifrado, e o payload é legível por qualquer um; o guia de JWT mostra por que confundir assinar com cifrar coloca dado sensível em lugar errado.

Senhas: hash lento com sal, nunca criptografia

O erro clássico é "criptografar a senha". Criptografia é reversível: se o servidor consegue voltar ao texto, um vazamento também consegue. O correto é guardar o hash da senha, para nunca guardar o valor real. Mas aqui está o ponto que separa o hash de senha do hash de arquivo: para um arquivo, você quer o hash rápido, porque só precisa verificar integridade em milissegundos. Para uma senha, "rápido" é justamente o defeito. Uma GPU calcula bilhões de SHA-256 por segundo; se o banco vaza, o atacante testa bilhões de palpites por segundo contra cada hash. O SHA-256 é ótimo para arquivo e péssimo para senha pelo mesmo motivo: velocidade.

A solução são funções feitas para senha: lentas de propósito, com um fator de custo ajustável e um sal aleatório por senha. O bcrypt (Provos e Mazières, 1999) foi o pioneiro; o scrypt (RFC 7914) e o Argon2 (RFC 9106, vencedor da Password Hashing Competition de 2015) são memory-hard, isto é, também exigem muita memória, o que estraga a vantagem das GPUs. O PBKDF2 (RFC 8018) é o mais antigo e só depende de iterações. A OWASP Password Storage Cheat Sheet recomenda hoje, como ponto de partida, os parâmetros da tabela:

Parâmetros mínimos recomendados pela OWASP (2025). Suba o custo até o hash levar algo em torno de 0,5 a 1 segundo no seu servidor.
FunçãoParâmetro de custo (mínimo)Quando escolher
Argon2id19 MiB de memória, 2 iterações, paralelismo 1Primeira escolha para código novo.
scryptN = 2^17, r = 8, p = 1Alternativa memory-hard quando não há Argon2.
bcryptfator de trabalho 10+ (limite de 72 bytes)Sistemas legados já com bcrypt.
PBKDF2-HMAC-SHA-256600.000 iterações ou maisQuando exige-se conformidade FIPS-140.
Sal (salt)
Valor aleatório e único por senha, guardado junto do hash. Faz duas senhas iguais gerarem hashes diferentes e inutiliza tabelas rainbow pré-calculadas.
Pimenta (pepper)
Segredo global do servidor, misturado à senha antes do hash e guardado FORA do banco. Se só o banco vaza, o hash sozinho não basta para o ataque.

Segundo exemplo trabalhado, com o valor real: se dois usuários escolhem a senha senha123, o SHA-256 de ambos é exatamente 55a5e9e7…4e6cd251, idêntico. O atacante calcula esse digest uma vez, procura na lista de hashes vazados e quebra os dois de uma vez; e como senha123 já está em toda tabela rainbow, isso é instantâneo. Agora adicione um sal aleatório por usuário: os hashes ficam diferentes, a tabela pré-calculada não serve, e o Argon2 obriga o atacante a gastar memória e tempo por palpite. O sal não deixa a senha mais forte, ele destrói a economia de escala do ataque.

  • Use Argon2id, scrypt ou bcrypt, nunca SHA-256 puro, para armazenar senha.
  • Um sal aleatório por senha, guardado junto do hash.
  • Nunca guarde senha em texto, Base64 ou MD5/SHA puro.
  • Suba o fator de custo até o hash levar de 0,5 a 1 segundo no seu servidor.

O gerador de bcrypt mostra como fica um hash de senha com sal e fator de custo embutidos na própria string. E, antes de guardar qualquer senha, o guia como escolher e testar uma senha forte ajuda o usuário a não entregar de bandeja a entrada que o atacante mais quer.

Length extension: por que hash(chave ‖ mensagem) falha e o HMAC conserta

MD5, SHA-1 e a família SHA-2 usam a construção Merkle–Damgård: processam a mensagem em blocos e o hash final é, essencialmente, o estado interno da máquina. O problema aparece quando alguém autentica uma mensagem com hash(chave ‖ mensagem). Um atacante que conhece esse hash e o tamanho da mensagem pode retomar o cálculo a partir do estado final e produzir um hash válido para hash(chave ‖ mensagem ‖ padding ‖ extensão), sem saber a chave. É o length extension attack, e ele forja mensagens autenticadas.

A correção padrão é o HMAC (RFC 2104), que aninha dois hashes com a chave e não expõe o estado interno como saída. Por isso o HMAC existe: não é "mais um hash", é a forma certa de usar um hash com chave. As construções mais novas nem precisam dele para isso: o SHA-3, por ser esponja, e o BLAKE2 não sofrem length extension por projeto.

Por que SHA-256 é péssimo para senha e ótimo para arquivo

É a mesma propriedade, velocidade, vista de dois ângulos. Para verificar um download de 4 GB, você quer o hash o mais rápido possível: SHA-256 processa o arquivo em um piscar e confirma a integridade. Para guardar uma senha, você quer o hash o mais lento possível: cada milissegundo a mais multiplica o custo de um ataque de força bruta. Como o SHA-256 é otimizado para velocidade, ele entrega ao atacante bilhões de tentativas por segundo em hardware barato. Funções de senha invertem isso de propósito, com fator de custo e (no scrypt e no Argon2) exigência de memória.

Modo ECB e o pinguim: por que nunca cifrar em ECB

O AES cifra blocos de 16 bytes. No modo ECB (Electronic Codebook), cada bloco de texto claro é cifrado isoladamente, então blocos iguais viram blocos de cifra iguais. Cifre uma imagem com áreas de cor uniforme (o clássico é o pinguim Tux do Linux) em AES-ECB e o contorno do pinguim continua visível no resultado cifrado: a criptografia escondeu os bytes, mas preservou o padrão. É a demonstração mais famosa de que ECB não deve ser usado.

A saída é usar um modo com IV aleatório e, de preferência, autenticado: AES-GCM, como faz a ferramenta de criptografia deste site. Cada execução produz um texto cifrado diferente para a mesma entrada, e a etiqueta de autenticação detecta adulteração.

Perguntas frequentes

Dá para descriptografar um hash SHA-256?
Não. Hash é irreversível por projeto; não há chave que o reverta. Quem "quebra" um hash na verdade adivinha a entrada e recalcula até bater, por isso senhas precisam de funções lentas com sal, que tornam esse chute-e-recalcula caro.
Base64 é criptografia?
Não. Base64 é encoding: público e reversível por qualquer pessoa, sem chave. Serve para representar bytes como texto (transporte, JSON, URL), não para proteger informação. Guardar senha em Base64 equivale a guardá-la em texto puro.
Por que não posso guardar senha com SHA-256?
Porque o SHA-256 é rápido demais: uma GPU calcula bilhões por segundo, então, se o banco vaza, o atacante testa bilhões de palpites por segundo. Além disso, sem sal, senhas iguais geram hashes iguais e caem em tabelas rainbow. Use Argon2id, scrypt ou bcrypt, com sal por senha.
O SHA-1 ainda é seguro?
Não para segurança. A resistência à colisão do SHA-1 caiu com o SHAttered (2017) e com o SHA-1 is a Shambles (2020), que fez uma colisão de prefixo escolhido por cerca de US$ 45 mil. Isso basta para forjar certificados e assinaturas. Use SHA-256 ou SHA-3.
Qual a diferença entre hash e HMAC?
Um hash simples prova integridade: mostra que os bytes não mudaram. O HMAC (RFC 2104) usa uma chave secreta, então prova integridade E autoria, só quem tem a chave gera um HMAC válido. Ele também evita o length extension attack, que afeta a construção ingênua hash(chave ‖ mensagem).
Qual hash usar para verificar um arquivo?
SHA-256 para garantia de segurança. O CRC32 só detecta erro acidental de transmissão e não resiste a adulteração intencional. Evite MD5 e SHA-1 para qualquer garantia de segurança, porque um atacante consegue forjar colisões.

Pergunte pela reversibilidade e pela chave: voltar sem segredo é encoding (transporte, não proteção); voltar só com a chave é criptografia (confidencialidade); não voltar de jeito nenhum é hashing (integridade). Senha nunca se criptografa, faz-se hash lento com sal em Argon2, scrypt ou bcrypt, porque o SHA-256 é rápido demais. E lembre que a colisão é a resistência mais frágil: foi ela que caiu no MD5 e no SHA-1.

Fontes e referências

  1. NIST FIPS 180-4, Secure Hash Standard (SHA-1, SHA-2)
  2. NIST FIPS 202, SHA-3 Standard (Keccak)
  3. The first collision for full SHA-1 (SHAttered), Stevens et al., 2017
  4. RFC 9106, Argon2 Memory-Hard Function for Password Hashing
  5. RFC 2104, HMAC: Keyed-Hashing for Message Authentication
  6. RFC 4648, The Base16, Base32, and Base64 Data Encodings
  7. OWASP, Password Storage Cheat Sheet