Codificar e decodificar uma string
printf '%s' 'héllo wörld' | openssl base64 # aMOpbGxvIHfDtnJsZA==
echo 'aMOpbGxvIHfDtnJsZA==' | openssl base64 -d # héllo wörld
openssl base64 é um atalho para openssl enc -base64; as duas formas aceitam as mesmas flags. Use printf '%s' ao codificar, para nenhuma quebra de linha entrar nos dados, e echo ao decodificar, pelo motivo explicado abaixo.
A armadilha da quebra de linha final e o -A
Por padrão, o OpenSSL processa Base64 como linhas de texto terminadas em quebra de linha. Uma última linha sem \n é ignorada na decodificação, então isto não imprime absolutamente nada:
printf 'aGVsbG8K' | openssl base64 -d # (no output)
printf 'aGVsbG8K\n' | openssl base64 -d # hello
printf 'aGVsbG8K' | openssl base64 -d -A # hello
O -A diz ao OpenSSL para tratar a entrada inteira como uma única linha. Use-o nas duas direções:
- Codificação: sem
-A, a saída é quebrada a cada 64 caracteres. Com-Avocê recebe uma linha só, que é o que headers HTTP, JSON e variáveis de ambiente precisam. - Decodificação: com
-A, a entrada precisa ser uma única linha, sem quebras. Sem-A, entrada em várias linhas, como o corpo de um PEM, decodifica normalmente.
head -c 60 /dev/zero | tr '\0' x | openssl base64 # 64 chars, newline, 16 chars
head -c 60 /dev/zero | tr '\0' x | openssl base64 -A # 80 chars on one line
A quebra a cada 64 caracteres segue o formato PEM (RFC 7468), não o MIME, que usa até 76. Para saída MIME, o codificador Base64 MIME ou o base64 do GNU (padrão 76) servem melhor.
Base64 URL-safe
O OpenSSL não tem modo Base64URL. Traduza com tr:
printf '%s' '<<???>>' | openssl base64 -A | tr '+/' '-_' | tr -d '='
# PDw_Pz8-Pg
Para decodificar, inverta o mapeamento e restaure o preenchimento; a página Base64 no Bash tem um laço que faz isso. O próprio OpenSSL ignora - e _ em silêncio, como mostrado abaixo, então nunca passe entrada URL-safe diretamente para ele. Base64 vs Base64URL explica a diferença.
Codificar e decodificar arquivos
openssl base64 -in photo.jpg -out photo.b64
openssl base64 -d -in photo.b64 -out photo-copy.jpg
O OpenSSL trabalha em fluxo, então arquivos grandes não são problema. Um arquivo aleatório de 100 KB sobreviveu à ida e volta byte a byte. O arquivo codificado é quebrado a cada 64 caracteres e termina com uma quebra de linha, então decodificá-lo sem -A funciona. Se você precisa de um arquivo em uma linha só, acrescente -A ao codificar e de novo ao decodificar.
Para um data URI:
printf 'data:image/jpeg;base64,%s' "$(openssl base64 -A -in photo.jpg)"
A seção BUGS do manual do enc no OpenSSL 3.5 ainda lista dois problemas relacionados: o -A “doesn’t work properly” (não funciona direito) com arquivos grandes, e, ao decodificar sem -A, se os primeiros 1024 bytes da entrada não tiverem nenhuma quebra de linha, as duas primeiras linhas são ignoradas. Para um arquivo grande em uma linha só, quebre-o antes com fold -w 64 e decodifique sem -A.
Falhas silenciosas: validar o resultado
O OpenSSL não acusa Base64 inválido. Ele para nos dados ruins, escreve o que conseguiu decodificar e sai com status 0. Resultados do OpenSSL 3.5:
| Entrada | Saída | Código de saída |
|---|---|---|
aGVsbG8K + quebra de linha | hello\n | 0 |
aGVsbG8K (sem quebra de linha) | nada | 0 |
aGk + quebra de linha (sem preenchimento) | nada | 0 |
aGk=!! + quebra de linha | nada | 0 |
PDw_Pz8-Pg== + quebra de linha (URL-safe) | nada | 0 |
not base64 at all + quebra de linha | nada | 0 |
Por isso, os scripts precisam conferir a saída por conta própria:
n=$(echo "$b64" | openssl base64 -d | wc -c)
[ "$n" -gt 0 ] || echo "decode failed or input was empty" >&2
Isso pega falhas completas, mas não as parciais, em que o OpenSSL decodificou um prefixo antes de encontrar dados ruins.
Ou mude para o base64 -d do GNU, que imprime base64: invalid input e sai com 1. Para ver o que há de errado com uma string específica, o validador de Base64 marca o caractere ruim, e erros comuns de Base64 explica as causas.
Hashes, chaves e saída criptografada
A maior parte do uso de Base64 no OpenSSL é em combinação com outros comandos:
printf '%s' hi | openssl dgst -sha256 -binary | openssl base64 -A
# j0NDRmSPa5bfid2pAcUXaxCm2Dlh3TwayItZstwyeqQ=
openssl rand -base64 32 # 32 random bytes -> 44 characters
A primeira forma gera digests SHA-256 em Base64, que é o que os hashes SRI e muitas assinaturas de API usam; a versão para o navegador é a ferramenta SHA-256 para Base64. O -binary é importante: sem ele, você codifica o texto hex do hash, não o hash.
openssl rand -base64 32 é uma forma comum de gerar segredos e chaves; o gerador de chaves Base64 faz o mesmo no navegador.
O openssl enc com -a (igual a -base64) codifica o texto cifrado em Base64:
printf '%s' 'secret text' | openssl enc -aes-256-cbc -pbkdf2 -a -pass pass:demo
# U2FsdGVkX1/eMk5T8FT9dX8OyAxLRn/ukvgmovOQOeA= (salt is random, changes every run)
O prefixo U2FsdGVkX1 é o Base64 de Salted__. Decodificá-lo sem a senha não revela nada legível. Essa diferença entre codificar e criptografar é explicada em codificação vs criptografia.
Arquivos PEM
Certificados e chaves no formato PEM são DER em Base64 entre linhas -----BEGIN ...-----, quebrado a cada 64 caracteres. O OpenSSL os converte diretamente, sem trabalho manual com Base64:
openssl x509 -in cert.pem -outform der -out cert.der
openssl x509 -in cert.der -inform der -outform pem
Para inspecionar um bloco PEM no navegador, use o decodificador de certificados ou PEM para DER.
Perguntas frequentes
Por que o openssl base64 -d não imprime nada?
Ou a entrada não tem quebra de linha no final, ou ela é inválida. Sem -A, o OpenSSL espera linhas terminadas em quebra de linha e descarta em silêncio uma última linha sem ela. Acrescente -A ou use echo em vez de printf '%s' para passar a string.
openssl base64 é o mesmo que openssl enc -base64?
Sim. openssl base64 é um atalho para openssl enc -base64, e os dois aceitam -d, -A, -in e -out.
Como saber se o openssl base64 -d deu certo?
Não dá para confiar no código de saída: entrada inválida retorna status 0 com saída vazia ou parcial. Confira se a saída não está vazia ou use o base64 -d do GNU, que sai com 1 quando a entrada é inválida.
O que é U2FsdGVkX1 no início de uma string Base64?
É o Base64 de Salted__, o header que o openssl enc escreve antes dos dados criptografados quando se usa uma senha. A string é texto cifrado, então decodificá-la dá ruído binário, não o texto original.